diff --git a/README.adoc b/README.adoc
index 642522587a8..13dc6410389 100644
--- a/README.adoc
+++ b/README.adoc
@@ -26,9 +26,13 @@ When installing GDS manually, please refer to the below compatibility matrix:
.Compatibility matrix (italicized version is in development)
|===
|GDS version | Neo4j version | Java Version
-.9+<.^|_GDS 2.4.x_
+.12+<.^|_GDS 2.4.x_
+|Neo4j 5.12.0
+.12+.^|Java 17
+|Neo4j 5.11.0
+|Neo4j 5.10.0
+|Neo4j 5.9.0
|Neo4j 5.8.0
-.8+.^|Java 17
|Neo4j 5.7.0
|Neo4j 5.6.0
|Neo4j 5.3.0
@@ -36,7 +40,7 @@ When installing GDS manually, please refer to the below compatibility matrix:
|Neo4j 5.4.0
|Neo4j 5.2.0
|Neo4j 5.1.0
-|Neo4j 4.4.9 - 4.4.21
+|Neo4j 4.4.9 - 4.4.26
.1+.^|Java 11
.9+<.^|GDS 2.3.x
|Neo4j 5.8.0
@@ -48,7 +52,7 @@ When installing GDS manually, please refer to the below compatibility matrix:
|Neo4j 5.3.0
|Neo4j 5.2.0
|Neo4j 5.1.0
-|Neo4j 4.4.9 - 4.4.21
+|Neo4j 4.4.9 - 4.4.23
.1+.^|Java 11
|===
@@ -93,7 +97,7 @@ For the most basic set of features, like graph loading and the graph representat
org.neo4j.gds
core
- 2.3.7
+ 2.4.6
----
@@ -105,21 +109,21 @@ The algorithms are located in the `algo-common`, `algo` and `alpha-algo` modules
org.neo4j.gds
algo-common
- 2.3.7
+ 2.4.6
org.neo4j.gds
algo
- 2.3.7
+ 2.4.6
org.neo4j.gds
alpha-algo
- 2.3.7
+ 2.4.6
----
@@ -131,28 +135,28 @@ The procedures are located in the `proc-common`, `proc` and `alpha-proc` modules
org.neo4j.gds
proc-common
- 2.3.7
+ 2.4.6
org.neo4j.gds
proc
- 2.3.7
+ 2.4.6
org.neo4j.gds
alpha-proc
- 2.3.7
+ 2.4.6
org.neo4j.gds
open-write-services
- 2.3.7
+ 2.4.6
----
diff --git a/algo-common/src/main/java/org/neo4j/gds/result/AbstractCentralityResultBuilder.java b/algo-common/src/main/java/org/neo4j/gds/result/AbstractCentralityResultBuilder.java
index c9c6b94c9df..7fb7529b9c7 100644
--- a/algo-common/src/main/java/org/neo4j/gds/result/AbstractCentralityResultBuilder.java
+++ b/algo-common/src/main/java/org/neo4j/gds/result/AbstractCentralityResultBuilder.java
@@ -22,7 +22,7 @@
import org.HdrHistogram.DoubleHistogram;
import org.jetbrains.annotations.NotNull;
import org.neo4j.gds.api.ProcedureReturnColumns;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.ProgressTimer;
import org.neo4j.gds.scaling.LogScaler;
import org.neo4j.gds.scaling.ScalerFactory;
@@ -95,7 +95,7 @@ private Optional computeCentralityHistogram() {
return Optional.of(CentralityStatistics.histogram(
nodeCount,
centralityFunction,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
concurrency
));
} catch (ArrayIndexOutOfBoundsException e) {
diff --git a/algo-common/src/main/java/org/neo4j/gds/result/AbstractCommunityResultBuilder.java b/algo-common/src/main/java/org/neo4j/gds/result/AbstractCommunityResultBuilder.java
index ae782035337..58ee87adef0 100644
--- a/algo-common/src/main/java/org/neo4j/gds/result/AbstractCommunityResultBuilder.java
+++ b/algo-common/src/main/java/org/neo4j/gds/result/AbstractCommunityResultBuilder.java
@@ -22,7 +22,7 @@
import org.HdrHistogram.Histogram;
import org.jetbrains.annotations.Nullable;
import org.neo4j.gds.api.ProcedureReturnColumns;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.ProgressTimer;
import java.util.Map;
@@ -54,7 +54,7 @@ protected AbstractCommunityResultBuilder(
ProcedureReturnColumns returnColumns,
int concurrency
) {
- this(returnColumns, Pools.DEFAULT, concurrency);
+ this(returnColumns, DefaultPool.INSTANCE, concurrency);
}
protected AbstractCommunityResultBuilder(
diff --git a/algo-common/src/main/java/org/neo4j/gds/scaling/ScalarScaler.java b/algo-common/src/main/java/org/neo4j/gds/scaling/ScalarScaler.java
index 0c003b08c97..d042eb2d099 100644
--- a/algo-common/src/main/java/org/neo4j/gds/scaling/ScalarScaler.java
+++ b/algo-common/src/main/java/org/neo4j/gds/scaling/ScalarScaler.java
@@ -25,7 +25,6 @@
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
public abstract class ScalarScaler implements Scaler {
@@ -72,13 +71,13 @@ abstract static class AggregatesComputer implements Runnable {
private final Partition partition;
private final NodePropertyValues properties;
private final ProgressTracker progressTracker;
- private final AtomicLong nodeCountOmittingMissingProperties;
+ private long nodeCountOmittingMissingProperties;
AggregatesComputer(Partition partition, NodePropertyValues property, ProgressTracker progressTracker) {
this.partition = partition;
this.properties = property;
this.progressTracker = progressTracker;
- this.nodeCountOmittingMissingProperties = new AtomicLong();
+ this.nodeCountOmittingMissingProperties = 0L;
}
abstract void compute(double propertyValue);
@@ -89,7 +88,7 @@ public void run() {
for (long nodeId = partition.startNode(); nodeId < end; nodeId++) {
var propertyValue = properties.doubleValue(nodeId);
if (!Double.isNaN(propertyValue)) {
- nodeCountOmittingMissingProperties.incrementAndGet();
+ ++nodeCountOmittingMissingProperties;
compute(propertyValue);
}
}
@@ -97,7 +96,7 @@ public void run() {
}
long nodeCountOmittingMissingValues() {
- return nodeCountOmittingMissingProperties.get();
+ return nodeCountOmittingMissingProperties;
}
}
}
diff --git a/algo-common/src/test/java/org/neo4j/gds/result/CommunityStatisticsTest.java b/algo-common/src/test/java/org/neo4j/gds/result/CommunityStatisticsTest.java
index ff833682001..5063bad3c1f 100644
--- a/algo-common/src/test/java/org/neo4j/gds/result/CommunityStatisticsTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/result/CommunityStatisticsTest.java
@@ -24,7 +24,7 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.TestSupport;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import java.util.HashMap;
import java.util.Map;
@@ -49,7 +49,7 @@ void communitySizes(
var communitySizes = CommunityStatistics.communitySizes(
nodeCount,
communityFunction,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
concurrency
);
expectedCommunitySizes.forEach((communityId, expectedSize) -> {
@@ -72,7 +72,7 @@ void communityCount(
CommunityStatistics.communityCount(
nodeCount,
communityFunction,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
concurrency
)
);
@@ -91,7 +91,7 @@ void communityCountAndHistogram(
var communityCountAndHistogram = CommunityStatistics.communityCountAndHistogram(
nodeCount,
communityFunction,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
concurrency
);
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/CenterTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/CenterTest.java
index 24159e087e6..20ad760ed70 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/CenterTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/CenterTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -63,7 +63,7 @@ void normalizes(NodePropertyValues properties, double avg, double[] expected) {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.avg).isEqualTo(avg);
@@ -81,7 +81,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var avg = 4.444;
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/L1NormTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/L1NormTest.java
index 1acf05847a2..10b7cef7416 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/L1NormTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/L1NormTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -62,7 +62,7 @@ void scale(int nodeCount, NodePropertyValues properties, double l1norm, double[]
nodeCount,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.l1Norm).isEqualTo(l1norm);
@@ -79,7 +79,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
for (int i = 0; i < 10; i++) {
@@ -95,7 +95,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var l1norm = 40D;
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/L2NormTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/L2NormTest.java
index 0808221440a..b8f93a15f2f 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/L2NormTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/L2NormTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -53,7 +53,7 @@ void normalizes(NodePropertyValues properties, double euclideanLength, double[]
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.euclideanLength).isEqualTo(euclideanLength);
@@ -70,7 +70,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
for (int i = 0; i < 10; i++) {
@@ -86,7 +86,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var euclideanLength = 16.124;
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/LogScalerTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/LogScalerTest.java
index 220eebde88f..680bfd05608 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/LogScalerTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/LogScalerTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
import org.neo4j.gds.nodeproperties.LongTestPropertyValues;
@@ -72,7 +72,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
for (int i = 0; i < 5; i++) {
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/MaxTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/MaxTest.java
index ba805420c8e..9d50bbb5afc 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/MaxTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/MaxTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -70,7 +70,7 @@ void scale(int nodeCount, NodePropertyValues properties, double absMax, double[]
nodeCount,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.maxAbs).isEqualTo(absMax);
@@ -88,7 +88,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.statistics()).containsExactlyEntriesOf(Map.of("absMax", List.of(0D)));
@@ -106,7 +106,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/MeanTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/MeanTest.java
index 80ac7bc12ab..39b5a4bf82c 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/MeanTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/MeanTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -57,7 +57,7 @@ void normalizes(NodePropertyValues properties, double avg, double min, double ma
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.avg).isEqualTo(avg);
@@ -81,7 +81,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.statistics()).containsExactlyInAnyOrderEntriesOf(Map.of(
@@ -103,7 +103,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var avg = 4.444;
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/MinMaxTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/MinMaxTest.java
index d2f0fe13f9a..edc881c051d 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/MinMaxTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/MinMaxTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -53,7 +53,7 @@ void normalizes(NodePropertyValues properties, double min, double max) {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.min).isEqualTo(min);
@@ -77,7 +77,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.statistics()).containsExactlyEntriesOf(Map.of(
@@ -98,7 +98,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/ScalerTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/ScalerTest.java
index c67bc368df1..a5f6c2966ab 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/ScalerTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/ScalerTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -39,14 +39,14 @@ void shouldAccumulateStatsCorrectly() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var meanScaler2 = (Mean) Mean.buildFrom(CypherMapWrapper.empty()).create(
new DoubleTestPropertyValues(nodeId -> 2 * nodeId),
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var meanScaler1Stats = meanScaler1.statistics();
diff --git a/algo-common/src/test/java/org/neo4j/gds/scaling/StdScoreTest.java b/algo-common/src/test/java/org/neo4j/gds/scaling/StdScoreTest.java
index 8495767c73b..236975d31ff 100644
--- a/algo-common/src/test/java/org/neo4j/gds/scaling/StdScoreTest.java
+++ b/algo-common/src/test/java/org/neo4j/gds/scaling/StdScoreTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.nodeproperties.DoubleTestPropertyValues;
@@ -56,7 +56,7 @@ void normalizes(NodePropertyValues properties, double avg, double std, double[]
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(scaler.avg).isEqualTo(avg);
@@ -78,7 +78,7 @@ void handlesMissingValue() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var avg = 4.444;
@@ -100,7 +100,7 @@ void avoidsDivByZero() {
10,
1,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
for (int i = 0; i < 10; i++) {
diff --git a/algo-test/src/main/java/org/neo4j/gds/test/TestMutateConfig.java b/algo-test/src/main/java/org/neo4j/gds/test/TestMutateConfig.java
index 31fd6d65d44..314e898be44 100644
--- a/algo-test/src/main/java/org/neo4j/gds/test/TestMutateConfig.java
+++ b/algo-test/src/main/java/org/neo4j/gds/test/TestMutateConfig.java
@@ -21,18 +21,18 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface TestMutateConfig extends TestConfig, MutatePropertyConfig {
+public interface TestMutateConfig extends TestConfig, MutateNodePropertyConfig {
default boolean throwOnEstimate() {
return false;
- };
-
+ }
+
static TestMutateConfig of(CypherMapWrapper config) {
return new TestMutateConfigImpl(config);
}
diff --git a/algo/src/main/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutFactory.java b/algo/src/main/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutFactory.java
index c8e6a41d9bf..617846da09a 100644
--- a/algo/src/main/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutFactory.java
@@ -24,7 +24,7 @@
import org.neo4j.gds.approxmaxkcut.config.ApproxMaxKCutConfig;
import org.neo4j.gds.collections.haa.HugeAtomicByteArray;
import org.neo4j.gds.collections.haa.HugeAtomicDoubleArray;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeByteArray;
@@ -51,7 +51,7 @@ public ApproxMaxKCut build(
CONFIG configuration,
ProgressTracker progressTracker
) {
- return new ApproxMaxKCut(graph, Pools.DEFAULT, configuration, progressTracker);
+ return new ApproxMaxKCut(graph, DefaultPool.INSTANCE, configuration, progressTracker);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/approxmaxkcut/config/ApproxMaxKCutMutateConfig.java b/algo/src/main/java/org/neo4j/gds/approxmaxkcut/config/ApproxMaxKCutMutateConfig.java
index 3c7856f4726..2eb2f468528 100644
--- a/algo/src/main/java/org/neo4j/gds/approxmaxkcut/config/ApproxMaxKCutMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/approxmaxkcut/config/ApproxMaxKCutMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface ApproxMaxKCutMutateConfig extends ApproxMaxKCutConfig, MutatePropertyConfig {
+public interface ApproxMaxKCutMutateConfig extends ApproxMaxKCutConfig, MutateNodePropertyConfig {
static ApproxMaxKCutMutateConfig of(CypherMapWrapper config) {
return new ApproxMaxKCutMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityFactory.java b/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityFactory.java
index 7925fc0cb21..9bae0ded336 100644
--- a/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityFactory.java
@@ -23,7 +23,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.collections.haa.HugeAtomicDoubleArray;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
@@ -66,7 +66,7 @@ public BetweennessCentrality build(
graph,
strategy,
traverserFactory,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
configuration.concurrency(),
progressTracker
);
diff --git a/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityMutateConfig.java b/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityMutateConfig.java
index 981f361ad42..b482d3bedd4 100644
--- a/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/betweenness/BetweennessCentralityMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface BetweennessCentralityMutateConfig extends BetweennessCentralityBaseConfig, MutatePropertyConfig {
+public interface BetweennessCentralityMutateConfig extends BetweennessCentralityBaseConfig, MutateNodePropertyConfig {
static BetweennessCentralityMutateConfig of(CypherMapWrapper config) {
return new BetweennessCentralityMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityFactory.java b/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityFactory.java
index c2219971cc2..df3bd6b0353 100644
--- a/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityFactory.java
@@ -22,7 +22,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
import org.neo4j.gds.core.utils.progress.tasks.Tasks;
@@ -37,7 +37,7 @@ public ClosenessCentrality build(
return ClosenessCentrality.of(
graph,
configuration,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityMutateConfig.java b/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityMutateConfig.java
index b1ffb92afeb..2e235b96446 100644
--- a/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/closeness/ClosenessCentralityMutateConfig.java
@@ -21,11 +21,11 @@
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
-public interface ClosenessCentralityMutateConfig extends ClosenessCentralityConfig, MutatePropertyConfig {
+public interface ClosenessCentralityMutateConfig extends ClosenessCentralityConfig, MutateNodePropertyConfig {
static ClosenessCentralityMutateConfig of(CypherMapWrapper config) {
return new ClosenessCentralityMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/conductance/ConductanceFactory.java b/algo/src/main/java/org/neo4j/gds/conductance/ConductanceFactory.java
index ace1f7357e5..a7d1050f318 100644
--- a/algo/src/main/java/org/neo4j/gds/conductance/ConductanceFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/conductance/ConductanceFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
import org.neo4j.gds.core.utils.progress.tasks.Tasks;
@@ -43,7 +43,7 @@ public Conductance build(
CONFIG configuration,
ProgressTracker progressTracker
) {
- return new Conductance(graph, Pools.DEFAULT, configuration, progressTracker);
+ return new Conductance(graph, DefaultPool.INSTANCE, configuration, progressTracker);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityFactory.java b/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityFactory.java
index 150061c5256..c3387586ad4 100644
--- a/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityFactory.java
@@ -22,7 +22,7 @@
import org.jetbrains.annotations.NotNull;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
@@ -45,7 +45,7 @@ public DegreeCentrality build(
CONFIG configuration,
ProgressTracker progressTracker
) {
- return new DegreeCentrality(graph, Pools.DEFAULT, configuration, progressTracker);
+ return new DegreeCentrality(graph, DefaultPool.INSTANCE, configuration, progressTracker);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityMutateConfig.java b/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityMutateConfig.java
index c74bb0d029b..1dc9ae7b10b 100644
--- a/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/degree/DegreeCentralityMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface DegreeCentralityMutateConfig extends DegreeCentralityConfig, MutatePropertyConfig {
+public interface DegreeCentralityMutateConfig extends DegreeCentralityConfig, MutateNodePropertyConfig {
static DegreeCentralityMutateConfig of(CypherMapWrapper config) {
return new DegreeCentralityMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRP.java b/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRP.java
index 34234604985..14c1e4375e9 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRP.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRP.java
@@ -22,8 +22,8 @@
import org.jetbrains.annotations.TestOnly;
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.ParallelUtil;
-import org.neo4j.gds.core.concurrency.Pools;
import org.neo4j.gds.core.concurrency.RunWithConcurrency;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -221,7 +221,7 @@ void propagateEmbeddings() {
);
ParallelUtil.parallelPartitionsConsume(
- RunWithConcurrency.builder().executor(Pools.DEFAULT).concurrency(concurrency),
+ RunWithConcurrency.builder().executor(DefaultPool.INSTANCE).concurrency(concurrency),
partitions.stream(),
taskSupplier
);
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRPMutateConfig.java b/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRPMutateConfig.java
index 96a22efff00..2cec7056641 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRPMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/fastrp/FastRPMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface FastRPMutateConfig extends FastRPBaseConfig, MutatePropertyConfig {
+public interface FastRPMutateConfig extends FastRPBaseConfig, MutateNodePropertyConfig {
static FastRPMutateConfig of(CypherMapWrapper userInput) {
return new FastRPMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageAlgorithmFactory.java
index 8d1736e0f40..f47eb2e3599 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageAlgorithmFactory.java
@@ -22,7 +22,7 @@
import org.neo4j.gds.GraphStoreAlgorithmFactory;
import org.neo4j.gds.api.GraphStore;
import org.neo4j.gds.config.MutateConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.model.ModelCatalog;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -49,7 +49,7 @@ public GraphSageAlgorithmFactory(ModelCatalog modelCatalog) {
@Override
public GraphSage build(GraphStore graphStore, CONFIG configuration, ProgressTracker progressTracker) {
- var executorService = Pools.DEFAULT;
+ var executorService = DefaultPool.INSTANCE;
var model = resolveModel(
modelCatalog,
configuration.modelUser(),
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageMutateConfig.java b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageMutateConfig.java
index 56c931feef4..23e10f6f4ff 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface GraphSageMutateConfig extends GraphSageBaseConfig, MutatePropertyConfig {
+public interface GraphSageMutateConfig extends GraphSageBaseConfig, MutateNodePropertyConfig {
long serialVersionUID = 0x42L;
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageTrainAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageTrainAlgorithmFactory.java
index d8ef87ba90c..358316dbe2c 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageTrainAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/graphsage/algo/GraphSageTrainAlgorithmFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -58,7 +58,7 @@ public GraphSageTrain build(
GraphSageTrainConfig configuration,
ProgressTracker progressTracker
) {
- var executorService = Pools.DEFAULT;
+ var executorService = DefaultPool.INSTANCE;
if(configuration.hasRelationshipWeightProperty()) {
validateRelationshipWeightPropertyValue(graph, configuration.concurrency(), executorService);
}
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/hashgnn/HashGNNMutateConfig.java b/algo/src/main/java/org/neo4j/gds/embeddings/hashgnn/HashGNNMutateConfig.java
index 3eb33296b00..425f687a1e2 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/hashgnn/HashGNNMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/hashgnn/HashGNNMutateConfig.java
@@ -20,11 +20,11 @@
package org.neo4j.gds.embeddings.hashgnn;
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
-public interface HashGNNMutateConfig extends HashGNNConfig, MutatePropertyConfig {
+public interface HashGNNMutateConfig extends HashGNNConfig, MutateNodePropertyConfig {
static HashGNNMutateConfig of(CypherMapWrapper config) {
return new HashGNNMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2Vec.java b/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2Vec.java
index 4b78949d26f..48f7d1cba55 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2Vec.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2Vec.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeObjectArray;
@@ -60,7 +60,7 @@ public Node2VecModel.Result compute() {
graph,
config,
progressTracker,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var probabilitiesBuilder = new RandomWalkProbabilities.Builder(
diff --git a/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2VecMutateConfig.java b/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2VecMutateConfig.java
index 6a75985f6d0..712926bea91 100644
--- a/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2VecMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/embeddings/node2vec/Node2VecMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface Node2VecMutateConfig extends Node2VecBaseConfig, MutatePropertyConfig {
+public interface Node2VecMutateConfig extends Node2VecBaseConfig, MutateNodePropertyConfig {
static Node2VecMutateConfig of(CypherMapWrapper userInput) {
return new Node2VecMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/harmonic/HarmonicCentralityAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/harmonic/HarmonicCentralityAlgorithmFactory.java
index 82ed47682a0..879f6fa54bd 100644
--- a/algo/src/main/java/org/neo4j/gds/harmonic/HarmonicCentralityAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/harmonic/HarmonicCentralityAlgorithmFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
public class HarmonicCentralityAlgorithmFactory extends GraphAlgorithmFactory {
@@ -39,7 +39,7 @@ public HarmonicCentrality build(
return new HarmonicCentrality(
graph,
configuration.concurrency(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/indexInverse/InverseRelationshipsAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/indexInverse/InverseRelationshipsAlgorithmFactory.java
index 8430d1e0f92..e1a9eb96a16 100644
--- a/algo/src/main/java/org/neo4j/gds/indexInverse/InverseRelationshipsAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/indexInverse/InverseRelationshipsAlgorithmFactory.java
@@ -23,7 +23,7 @@
import org.neo4j.gds.GraphStoreAlgorithmFactory;
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.GraphStore;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.AdjacencyListBehavior;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -45,7 +45,7 @@ public InverseRelationships build(
InverseRelationshipsConfig configuration,
ProgressTracker progressTracker
) {
- return new InverseRelationships(graphStore, configuration, progressTracker, Pools.DEFAULT);
+ return new InverseRelationships(graphStore, configuration, progressTracker, DefaultPool.INSTANCE);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELF.java b/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELF.java
index ffccd82a491..4cedaee5b3f 100644
--- a/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELF.java
+++ b/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELF.java
@@ -31,8 +31,6 @@
import java.util.Optional;
import java.util.concurrent.ExecutorService;
-import java.util.stream.LongStream;
-import java.util.stream.Stream;
public class CELF extends Algorithm {
@@ -185,12 +183,4 @@ private void lazyForwardPart(long firstSeedNode) {
}
progressTracker.endSubTask();
}
-
- public Stream resultStream() {
- return LongStream.of(seedSetNodes.keys().toArray())
- .mapToObj(node -> new InfluenceMaximizationResult(
- graph.toOriginalNodeId(node),
- seedSetNodes.getOrDefault(node, 0)
- ));
- }
}
diff --git a/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELFAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELFAlgorithmFactory.java
index 69e3692a5b3..f479f7d5d6d 100644
--- a/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELFAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/influenceMaximization/CELFAlgorithmFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -53,7 +53,7 @@ public CELF build(
configuration.seedSetSize(),
configuration.propagationProbability(),
configuration.monteCarloSimulations(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
configuration.concurrency(),
configuration.randomSeed().orElse(0L),
DEFAULT_BATCH_SIZE,
diff --git a/algo/src/main/java/org/neo4j/gds/influenceMaximization/InfluenceMaximizationMutateConfig.java b/algo/src/main/java/org/neo4j/gds/influenceMaximization/InfluenceMaximizationMutateConfig.java
index 97c901db9d0..d8b1f85df13 100644
--- a/algo/src/main/java/org/neo4j/gds/influenceMaximization/InfluenceMaximizationMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/influenceMaximization/InfluenceMaximizationMutateConfig.java
@@ -20,11 +20,11 @@
package org.neo4j.gds.influenceMaximization;
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
-public interface InfluenceMaximizationMutateConfig extends InfluenceMaximizationBaseConfig, MutatePropertyConfig {
+public interface InfluenceMaximizationMutateConfig extends InfluenceMaximizationBaseConfig, MutateNodePropertyConfig {
static InfluenceMaximizationMutateConfig of(CypherMapWrapper userInput) {
return new InfluenceMaximizationMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringFactory.java b/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringFactory.java
index 1f532f1c713..2e4e0694855 100644
--- a/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringFactory.java
@@ -23,7 +23,7 @@
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.config.BaseConfig;
import org.neo4j.gds.config.IterationsConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -54,7 +54,7 @@ public K1Coloring build(
configuration.maxIterations(),
configuration.batchSize(),
configuration.concurrency(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringMutateConfig.java b/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringMutateConfig.java
index 519a7ca256c..38330a18072 100644
--- a/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/k1coloring/K1ColoringMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface K1ColoringMutateConfig extends K1ColoringConfig, MutatePropertyConfig {
+public interface K1ColoringMutateConfig extends K1ColoringConfig, MutateNodePropertyConfig {
static K1ColoringMutateConfig of(CypherMapWrapper userInput) {
return new K1ColoringMutateConfigImpl(userInput);
}
diff --git a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecomposition.java b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecomposition.java
index c3da74dcfbd..cde9cf42b1e 100644
--- a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecomposition.java
+++ b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecomposition.java
@@ -116,6 +116,7 @@ public KCoreDecompositionResult compute() {
for (var task : tasks) {
task.setScanningDegree(scanningDegree);
+ task.setPhase(KCoreDecompositionTask.KCoreDecompositionPhase.SCAN);
}
RunWithConcurrency.builder().tasks(tasks).concurrency(concurrency).run();
@@ -129,8 +130,14 @@ public KCoreDecompositionResult compute() {
if (nextScanningDegree == scanningDegree) {
degeneracy = scanningDegree;
+
+ for (var task : tasks) {
+ task.setPhase(KCoreDecompositionTask.KCoreDecompositionPhase.ACT);
+ }
+
RunWithConcurrency.builder().tasks(tasks).concurrency(concurrency).run();
scanningDegree++;
+
} else {
//this is a minor optimization not in paper:
// if we do not do any updates this round, let's skip directly to the smallest active degree remaining
diff --git a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionMutateConfig.java b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionMutateConfig.java
index bcd8ea2aadb..584973a1c9b 100644
--- a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionMutateConfig.java
@@ -20,11 +20,11 @@
package org.neo4j.gds.kcore;
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
-public interface KCoreDecompositionMutateConfig extends KCoreDecompositionBaseConfig, MutatePropertyConfig {
+public interface KCoreDecompositionMutateConfig extends KCoreDecompositionBaseConfig, MutateNodePropertyConfig {
static KCoreDecompositionMutateConfig of(CypherMapWrapper userInput) {
return new KCoreDecompositionMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionTask.java b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionTask.java
index 3f5f9dacb22..854b08dfe93 100644
--- a/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionTask.java
+++ b/algo/src/main/java/org/neo4j/gds/kcore/KCoreDecompositionTask.java
@@ -80,13 +80,15 @@ void updateNodeProvider(NodeProvider nodeProvider) {
public void run() {
if (phase == KCoreDecompositionPhase.SCAN) {
scan();
- phase = KCoreDecompositionPhase.ACT;
} else {
act();
- phase = KCoreDecompositionPhase.SCAN;
}
}
+ void setPhase(KCoreDecompositionPhase phase) {
+ this.phase = phase;
+ }
+
private void scan() {
long upperBound = nodeProvider.size();
diff --git a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansAlgorithmFactory.java
index b1f5d26521d..25aab9a298f 100644
--- a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansAlgorithmFactory.java
@@ -22,7 +22,7 @@
import org.jetbrains.annotations.NotNull;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
@@ -61,7 +61,7 @@ public Kmeans build(
return Kmeans.createKmeans(graph, configuration, ImmutableKmeansContext
.builder()
.progressTracker(progressTracker)
- .executor(Pools.DEFAULT)
+ .executor(DefaultPool.INSTANCE)
.build());
}
diff --git a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansContext.java b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansContext.java
index d90627dfefb..b5729e27c47 100644
--- a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansContext.java
+++ b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansContext.java
@@ -21,7 +21,7 @@
import org.immutables.value.Value;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import java.util.concurrent.ExecutorService;
@@ -31,7 +31,7 @@ public interface KmeansContext {
@Value.Default
default ExecutorService executor() {
- return Pools.DEFAULT;
+ return DefaultPool.INSTANCE;
}
@Value.Default
diff --git a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansMutateConfig.java b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansMutateConfig.java
index 04eb8a32a68..e77279582ec 100644
--- a/algo/src/main/java/org/neo4j/gds/kmeans/KmeansMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/kmeans/KmeansMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface KmeansMutateConfig extends KmeansBaseConfig, MutatePropertyConfig {
+public interface KmeansMutateConfig extends KmeansBaseConfig, MutateNodePropertyConfig {
static KmeansMutateConfig of(CypherMapWrapper userInput) {
return new KmeansMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/kspanningtree/KSpanningTree.java b/algo/src/main/java/org/neo4j/gds/kspanningtree/KSpanningTree.java
index dcdbd4f4650..13560970dd3 100644
--- a/algo/src/main/java/org/neo4j/gds/kspanningtree/KSpanningTree.java
+++ b/algo/src/main/java/org/neo4j/gds/kspanningtree/KSpanningTree.java
@@ -58,7 +58,7 @@ public KSpanningTree(
super(progressTracker);
this.graph = graph;
this.minMax = minMax;
- this.startNodeId = (int) graph.toMappedNodeId(startNodeId);
+ this.startNodeId = startNodeId;
this.k = k;
}
diff --git a/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationFactory.java b/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationFactory.java
index 33c1a0db598..08232a8ab0f 100644
--- a/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationFactory.java
@@ -22,7 +22,7 @@
import com.carrotsearch.hppc.LongDoubleScatterMap;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -53,7 +53,7 @@ public LabelPropagation build(
return new LabelPropagation(
graph,
configuration,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationMutateConfig.java b/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationMutateConfig.java
index a5a910e60c0..5cc34e56d6b 100644
--- a/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/labelpropagation/LabelPropagationMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface LabelPropagationMutateConfig extends LabelPropagationBaseConfig, MutatePropertyConfig {
+public interface LabelPropagationMutateConfig extends LabelPropagationBaseConfig, MutateNodePropertyConfig {
static LabelPropagationMutateConfig of(CypherMapWrapper userInput) {
return new LabelPropagationMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/leiden/Leiden.java b/algo/src/main/java/org/neo4j/gds/leiden/Leiden.java
index 5fd0d037076..b9b27794150 100644
--- a/algo/src/main/java/org/neo4j/gds/leiden/Leiden.java
+++ b/algo/src/main/java/org/neo4j/gds/leiden/Leiden.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.api.schema.Direction;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.RunWithConcurrency;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -77,7 +77,7 @@ public Leiden(
this.theta = theta;
this.randomSeed = randomSeed;
// TODO: Pass these two as parameters
- this.executorService = Pools.DEFAULT;
+ this.executorService = DefaultPool.INSTANCE;
this.concurrency = concurrency;
this.dendrogramManager = new LeidenDendrogramManager(
rootGraph,
diff --git a/algo/src/main/java/org/neo4j/gds/leiden/LeidenMutateConfig.java b/algo/src/main/java/org/neo4j/gds/leiden/LeidenMutateConfig.java
index 0f14102d0f2..0ee812a5342 100644
--- a/algo/src/main/java/org/neo4j/gds/leiden/LeidenMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/leiden/LeidenMutateConfig.java
@@ -20,11 +20,11 @@
package org.neo4j.gds.leiden;
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
-public interface LeidenMutateConfig extends LeidenBaseConfig, MutatePropertyConfig {
+public interface LeidenMutateConfig extends LeidenBaseConfig, MutateNodePropertyConfig {
static LeidenMutateConfig of(CypherMapWrapper userInput) {
return new LeidenMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/louvain/LouvainAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/louvain/LouvainAlgorithmFactory.java
index 9898c9e3db5..7d8e79dda4f 100644
--- a/algo/src/main/java/org/neo4j/gds/louvain/LouvainAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/louvain/LouvainAlgorithmFactory.java
@@ -31,7 +31,7 @@
import org.neo4j.gds.core.Aggregation;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.NativeFactory;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -61,7 +61,7 @@ public Louvain build(
configuration.tolerance(),
configuration.concurrency(),
progressTracker,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/louvain/LouvainMutateConfig.java b/algo/src/main/java/org/neo4j/gds/louvain/LouvainMutateConfig.java
index 3ee19b17901..0b8d575869e 100644
--- a/algo/src/main/java/org/neo4j/gds/louvain/LouvainMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/louvain/LouvainMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface LouvainMutateConfig extends LouvainBaseConfig, MutatePropertyConfig {
+public interface LouvainMutateConfig extends LouvainBaseConfig, MutateNodePropertyConfig {
static LouvainMutateConfig of(CypherMapWrapper userInput) {
return new LouvainMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationFactory.java b/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationFactory.java
index 17fa061e0ed..e3047b883c9 100644
--- a/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationFactory.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.collections.haa.HugeAtomicDoubleArray;
import org.neo4j.gds.config.BaseConfig;
import org.neo4j.gds.config.IterationsConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -106,7 +106,7 @@ public ModularityOptimization build(
seedProperty,
configuration.concurrency(),
configuration.batchSize(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationMutateConfig.java b/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationMutateConfig.java
index 9e0ac155dcc..e74d936d5ee 100644
--- a/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface ModularityOptimizationMutateConfig extends ModularityOptimizationConfig, MutatePropertyConfig {
+public interface ModularityOptimizationMutateConfig extends ModularityOptimizationConfig, MutateNodePropertyConfig {
static ModularityOptimizationMutateConfig of(CypherMapWrapper userInput) {
return new ModularityOptimizationMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/pagerank/PageRankAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/pagerank/PageRankAlgorithmFactory.java
index e076c0856e5..6ead19c2b5c 100644
--- a/algo/src/main/java/org/neo4j/gds/pagerank/PageRankAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/pagerank/PageRankAlgorithmFactory.java
@@ -27,8 +27,8 @@
import org.neo4j.gds.beta.pregel.Pregel;
import org.neo4j.gds.beta.pregel.PregelComputation;
import org.neo4j.gds.beta.pregel.PregelSchema;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.ParallelUtil;
-import org.neo4j.gds.core.concurrency.Pools;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -44,9 +44,6 @@
public class PageRankAlgorithmFactory extends GraphAlgorithmFactory {
- static Task pagerankProgressTask(Graph graph, CONFIG config) {
- return Pregel.progressTask(graph, config, "PageRank");
- }
private static double averageDegree(Graph graph, int concurrency) {
var degreeSum = new LongAdder();
@@ -60,9 +57,19 @@ private static double averageDegree(Graph graph, int concurrency) {
}
public enum Mode {
- PAGE_RANK,
- ARTICLE_RANK,
- EIGENVECTOR,
+ PAGE_RANK("PageRank"),
+ ARTICLE_RANK("ArticleRank"),
+ EIGENVECTOR("EigenVector");
+
+ private final String taskName;
+
+ Mode(String taskName) {
+ this.taskName = taskName;
+ }
+
+ String taskName() {
+ return taskName;
+ }
}
private final Mode mode;
@@ -77,7 +84,7 @@ public PageRankAlgorithmFactory(Mode mode) {
@Override
public String taskName() {
- return mode.name();
+ return mode.taskName();
}
@Override
@@ -121,14 +128,14 @@ public PageRankAlgorithm build(
configuration,
computation,
mode,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
@Override
public Task progressTask(Graph graph, CONFIG config) {
- return pagerankProgressTask(graph, config);
+ return Pregel.progressTask(graph, config, taskName());
}
@NotNull
@@ -143,7 +150,7 @@ private LongToDoubleFunction degreeFunction(
var degreeCentrality = new DegreeCentrality(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/main/java/org/neo4j/gds/pagerank/PageRankMutateConfig.java b/algo/src/main/java/org/neo4j/gds/pagerank/PageRankMutateConfig.java
index 4179283b83d..8e4714eed95 100644
--- a/algo/src/main/java/org/neo4j/gds/pagerank/PageRankMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/pagerank/PageRankMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface PageRankMutateConfig extends PageRankConfig, MutatePropertyConfig {
+public interface PageRankMutateConfig extends PageRankConfig, MutateNodePropertyConfig {
static PageRankMutateConfig of(CypherMapWrapper userInput) {
return new PageRankMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/paths/delta/DeltaSteppingFactory.java b/algo/src/main/java/org/neo4j/gds/paths/delta/DeltaSteppingFactory.java
index b7d38aba171..23456c2dd14 100644
--- a/algo/src/main/java/org/neo4j/gds/paths/delta/DeltaSteppingFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/paths/delta/DeltaSteppingFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
@@ -38,7 +38,7 @@ public DeltaStepping build(
T configuration,
ProgressTracker progressTracker
) {
- return DeltaStepping.of(graph, configuration, Pools.DEFAULT, progressTracker);
+ return DeltaStepping.of(graph, configuration, DefaultPool.INSTANCE, progressTracker);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/paths/traverse/BFS.java b/algo/src/main/java/org/neo4j/gds/paths/traverse/BFS.java
index 4f21860c24a..15ea38e5e36 100644
--- a/algo/src/main/java/org/neo4j/gds/paths/traverse/BFS.java
+++ b/algo/src/main/java/org/neo4j/gds/paths/traverse/BFS.java
@@ -23,8 +23,8 @@
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.collections.haa.HugeAtomicLongArray;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.ParallelUtil;
-import org.neo4j.gds.core.concurrency.Pools;
import org.neo4j.gds.core.utils.paged.HugeAtomicBitSet;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -199,7 +199,7 @@ public HugeLongArray compute() {
if (currentDepth == maximumDepth) {
break;
}
- ParallelUtil.run(bfsTaskList, Pools.DEFAULT);
+ ParallelUtil.run(bfsTaskList, DefaultPool.INSTANCE);
if (targetFoundIndex.get() != Long.MAX_VALUE) {
break;
diff --git a/algo/src/main/java/org/neo4j/gds/paths/yens/Yens.java b/algo/src/main/java/org/neo4j/gds/paths/yens/Yens.java
index 7eb0cf73b97..a07aa9bfcee 100644
--- a/algo/src/main/java/org/neo4j/gds/paths/yens/Yens.java
+++ b/algo/src/main/java/org/neo4j/gds/paths/yens/Yens.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.RunWithConcurrency;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -113,7 +113,7 @@ public PathFindingResult compute() {
RunWithConcurrency.builder()
.concurrency(config.concurrency())
.tasks(tasks)
- .executor(Pools.DEFAULT)
+ .executor(DefaultPool.INSTANCE)
.run();
progressTracker.logProgress();
diff --git a/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesFactory.java b/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesFactory.java
index 99f7dbb2498..745c32c2a85 100644
--- a/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -69,7 +69,7 @@ public ScaleProperties build(
graph,
configuration,
progressTracker,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesMutateConfig.java b/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesMutateConfig.java
index d71b9192c01..cb55d86186f 100644
--- a/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/scaleproperties/ScalePropertiesMutateConfig.java
@@ -20,12 +20,12 @@
package org.neo4j.gds.scaleproperties;
import org.neo4j.gds.annotation.Configuration;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface ScalePropertiesMutateConfig extends ScalePropertiesBaseConfig, MutatePropertyConfig {
+public interface ScalePropertiesMutateConfig extends ScalePropertiesBaseConfig, MutateNodePropertyConfig {
static ScalePropertiesMutateConfig of(CypherMapWrapper userInput) {
return new ScalePropertiesMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnFactory.java b/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnFactory.java
index ef6dbe66a79..056fac86cbf 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnFactory.java
@@ -23,7 +23,7 @@
import org.apache.commons.lang3.function.TriFunction;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -68,7 +68,7 @@ public FilteredKnn build(Graph graph, CONFIG configuration, ProgressTracker prog
KnnContext knnContext = ImmutableKnnContext
.builder()
.progressTracker(progressTracker)
- .executor(Pools.DEFAULT)
+ .executor(DefaultPool.INSTANCE)
.build();
if (configuration.seedTargetNodes()) {
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnMutateConfig.java b/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnMutateConfig.java
index 2ed1e183ead..d94c0992432 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/filteredknn/FilteredKnnMutateConfig.java
@@ -21,14 +21,15 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
import org.neo4j.gds.config.MutateRelationshipConfig;
+import org.neo4j.gds.config.MutateRelationshipPropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface FilteredKnnMutateConfig extends FilteredKnnBaseConfig, MutatePropertyConfig, MutateRelationshipConfig {
+public interface FilteredKnnMutateConfig extends FilteredKnnBaseConfig,
+ MutateRelationshipPropertyConfig, MutateRelationshipConfig {
static FilteredKnnMutateConfig of(CypherMapWrapper config) {
return new FilteredKnnMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/filterednodesim/FilteredNodeSimilarityFactory.java b/algo/src/main/java/org/neo4j/gds/similarity/filterednodesim/FilteredNodeSimilarityFactory.java
index 9e4940c9143..42eac124cb9 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/filterednodesim/FilteredNodeSimilarityFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/filterednodesim/FilteredNodeSimilarityFactory.java
@@ -22,7 +22,7 @@
import com.carrotsearch.hppc.BitSet;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -59,7 +59,7 @@ public NodeSimilarity build(
configuration.sourceNodeFilter().toNodeFilter(graph),
configuration.targetNodeFilter().toNodeFilter(graph),
configuration.concurrency(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnContext.java b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnContext.java
index cab6b05a4f7..54acdbc5726 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnContext.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnContext.java
@@ -21,7 +21,7 @@
import org.immutables.value.Value;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import java.util.concurrent.ExecutorService;
@@ -31,7 +31,7 @@ public interface KnnContext {
@Value.Default
default ExecutorService executor() {
- return Pools.DEFAULT;
+ return DefaultPool.INSTANCE;
}
@Value.Default
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnFactory.java b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnFactory.java
index d09bff5787d..8dded7f2ec8 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnFactory.java
@@ -22,7 +22,7 @@
import com.carrotsearch.hppc.LongArrayList;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -59,7 +59,7 @@ public Knn build(
ImmutableKnnContext
.builder()
.progressTracker(progressTracker)
- .executor(Pools.DEFAULT)
+ .executor(DefaultPool.INSTANCE)
.build()
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnMutateConfig.java b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnMutateConfig.java
index 8cf2746da65..39b7c9d277e 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/knn/KnnMutateConfig.java
@@ -21,14 +21,14 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
import org.neo4j.gds.config.MutateRelationshipConfig;
+import org.neo4j.gds.config.MutateRelationshipPropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface KnnMutateConfig extends KnnBaseConfig, MutatePropertyConfig, MutateRelationshipConfig {
+public interface KnnMutateConfig extends KnnBaseConfig, MutateRelationshipPropertyConfig, MutateRelationshipConfig {
static KnnMutateConfig of(CypherMapWrapper config) {
return new KnnMutateConfigImpl(config);
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/knn/metrics/Euclidean.java b/algo/src/main/java/org/neo4j/gds/similarity/knn/metrics/Euclidean.java
index 39c85fbaaea..48524b2632d 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/knn/metrics/Euclidean.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/knn/metrics/Euclidean.java
@@ -19,6 +19,8 @@
*/
package org.neo4j.gds.similarity.knn.metrics;
+import java.util.function.IntToDoubleFunction;
+
/**
* Here we calculate Euclidean similarity metrics using Euclidean dictance as described in e.g.
* https://en.wikipedia.org/wiki/Euclidean_distance
@@ -33,22 +35,28 @@ public final class Euclidean {
private Euclidean() {}
public static double floatMetric(float[] left, float[] right) {
- var len = Math.min(left.length, right.length);
- var result = 0D;
- for (int i = 0; i < len; i++) {
- double delta = left[i] - right[i];
- result += delta * delta;
- }
- return 1.0 / (1.0 + result);
+ return compute(
+ Math.min(left.length, right.length),
+ i -> left[i],
+ i -> right[i]
+ );
}
public static double doubleMetric(double[] left, double[] right) {
- var len = Math.min(left.length, right.length);
+ return compute(
+ Math.min(left.length, right.length),
+ i -> left[i],
+ i -> right[i]
+ );
+ }
+
+ private static double compute(int len, IntToDoubleFunction left, IntToDoubleFunction right) {
var result = 0D;
for (int i = 0; i < len; i++) {
- double delta = left[i] - right[i];
+ double delta = left.applyAsDouble(i) - right.applyAsDouble(i);
result += delta * delta;
}
- return 1.0 / (1.0 + result);
+
+ return 1.0 / (1.0 + Math.sqrt(result));
}
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputer.java b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputer.java
new file mode 100644
index 00000000000..2279547d23a
--- /dev/null
+++ b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputer.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.similarity.nodesim;
+
+import org.neo4j.gds.core.utils.Intersections;
+
+public class CosineSimilarityComputer implements MetricSimilarityComputer {
+ private final double similarityCutoff;
+
+ public CosineSimilarityComputer(double similarityCutoff) {
+ this.similarityCutoff = similarityCutoff;
+ }
+
+ @Override
+ public double computeSimilarity(long[] vector1, long[] vector2) {
+ var intersection = Intersections.intersection3(vector1, vector2);
+ var similarity = intersection / (Math.sqrt(vector1.length) * Math.sqrt(vector2.length));
+ return similarity >= similarityCutoff ? similarity : Double.NaN;
+ }
+
+ @Override
+ public double computeWeightedSimilarity(long[] vector1, long[] vector2, double[] weights1, double[] weights2) {
+ assert vector1.length == weights1.length;
+ assert vector2.length == weights2.length;
+
+ double vector1SquaredSum = 0;
+ double vector2SquaredSum = 0;
+ double above=0;
+
+ int offset1 = 0;
+ int offset2 = 0;
+ int length1 = weights1.length;
+ int length2 = weights2.length;
+
+ while (offset1 < length1 && offset2 < length2) {
+ long target1 = vector1[offset1];
+ long target2 = vector2[offset2];
+ double w1 = weights1[offset1];
+ double w2 = weights2[offset2];
+
+ if (target1 == target2) {
+ above+=w1*w2;
+ vector1SquaredSum+= w1*w1;
+ vector2SquaredSum+= w2*w2;
+ offset1++;
+ offset2++;
+ } else if (target1 < target2) {
+ vector1SquaredSum += w1*w1;
+ offset1++;
+ } else {
+ vector2SquaredSum += w2*w2;
+ offset2++;
+ }
+ }
+
+ for (; offset1 < length1; offset1++) {
+ vector1SquaredSum += weights1[offset1] * weights1[offset1];
+ }
+ for (; offset2 < length2; offset2++) {
+ vector2SquaredSum += weights2[offset2]* weights2[offset2];
+ }
+
+
+ double similarity = above/(Math.sqrt(vector1SquaredSum) * Math.sqrt(vector2SquaredSum));
+ return similarity >= similarityCutoff ? similarity : Double.NaN;
+
+ }
+
+ static class Builder implements MetricSimilarityComputerBuilder {
+ public MetricSimilarityComputer build(double similarityCutoff) {
+ return new CosineSimilarityComputer(similarityCutoff);
+ }
+
+ @Override
+ public String render() {
+ return "COSINE";
+ }
+ }
+}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputer.java b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputer.java
index a1d2626385f..191491f4cfc 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputer.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputer.java
@@ -50,6 +50,8 @@ private static NodeSimilarityMetric valueOf(String userInput) {
return NodeSimilarityMetric.JACCARD;
} else if (userInputInCaps.equals("OVERLAP")) {
return NodeSimilarityMetric.OVERLAP;
+ } else if (userInputInCaps.equals("COSINE")) {
+ return NodeSimilarityMetric.COSINE;
} else {
throw new IllegalArgumentException(userInput + " is not a valid metric. Available metrics include Jaccard and Overlap");
}
@@ -58,8 +60,10 @@ private static NodeSimilarityMetric valueOf(String userInput) {
private static MetricSimilarityComputerBuilder create(NodeSimilarityMetric metric) {
if (metric == NodeSimilarityMetric.JACCARD) {
return new JaccardSimilarityComputer.Builder();
- } else {
+ } else if (metric == NodeSimilarityMetric.OVERLAP) {
return new OverlapSimilarityComputer.Builder();
+ } else {
+ return new CosineSimilarityComputer.Builder();
}
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityFactory.java b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityFactory.java
index 4da718731e9..b1eb71e31f2 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityFactory.java
@@ -22,7 +22,7 @@
import com.carrotsearch.hppc.BitSet;
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -54,7 +54,7 @@ public NodeSimilarity build(
configuration,
similarityComputer,
configuration.concurrency(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMetric.java b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMetric.java
index 19024e0d01e..54de85d4455 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMetric.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMetric.java
@@ -21,5 +21,6 @@
public enum NodeSimilarityMetric {
JACCARD,
- OVERLAP
+ OVERLAP,
+ COSINE,
}
diff --git a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMutateConfig.java b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMutateConfig.java
index ab5ec264d8f..02fb3422315 100644
--- a/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityMutateConfig.java
@@ -21,14 +21,15 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
import org.neo4j.gds.config.MutateRelationshipConfig;
+import org.neo4j.gds.config.MutateRelationshipPropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface NodeSimilarityMutateConfig extends NodeSimilarityBaseConfig, MutatePropertyConfig, MutateRelationshipConfig {
+public interface NodeSimilarityMutateConfig extends NodeSimilarityBaseConfig,
+ MutateRelationshipPropertyConfig, MutateRelationshipConfig {
static NodeSimilarityMutateConfig of(CypherMapWrapper userInput) {
NodeSimilarityMutateConfig config = new NodeSimilarityMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/spanningtree/SpanningTreeMutateConfig.java b/algo/src/main/java/org/neo4j/gds/spanningtree/SpanningTreeMutateConfig.java
index 0477c38dcff..c12d7b3dcdb 100644
--- a/algo/src/main/java/org/neo4j/gds/spanningtree/SpanningTreeMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/spanningtree/SpanningTreeMutateConfig.java
@@ -21,14 +21,15 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
import org.neo4j.gds.config.MutateRelationshipConfig;
+import org.neo4j.gds.config.MutateRelationshipPropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface SpanningTreeMutateConfig extends SpanningTreeBaseConfig, MutatePropertyConfig, MutateRelationshipConfig {
+public interface SpanningTreeMutateConfig extends SpanningTreeBaseConfig,
+ MutateRelationshipPropertyConfig, MutateRelationshipConfig {
static SpanningTreeMutateConfig of(CypherMapWrapper userInput) {
return new SpanningTreeMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeAlgorithmFactory.java
index b0fa97c7ebd..60e0761b4b8 100644
--- a/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeAlgorithmFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
import org.neo4j.gds.core.utils.progress.tasks.Tasks;
@@ -51,7 +51,7 @@ public ShortestPathsSteinerAlgorithm build(
configuration.delta(),
configuration.concurrency(),
configuration.applyRerouting(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeMutateConfig.java b/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeMutateConfig.java
index 4a08ee51630..b85d996f34f 100644
--- a/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/steiner/SteinerTreeMutateConfig.java
@@ -21,14 +21,16 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
import org.neo4j.gds.config.MutateRelationshipConfig;
+import org.neo4j.gds.config.MutateRelationshipPropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface SteinerTreeMutateConfig extends SteinerTreeBaseConfig, MutateRelationshipConfig, MutatePropertyConfig {
+public interface SteinerTreeMutateConfig extends SteinerTreeBaseConfig,
+ MutateRelationshipConfig,
+ MutateRelationshipPropertyConfig {
static SteinerTreeMutateConfig of(CypherMapWrapper userInput) {
return new SteinerTreeMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/topologicalsort/TopologicalSort.java b/algo/src/main/java/org/neo4j/gds/topologicalsort/TopologicalSort.java
index 86f7c36258d..5a9f1f3e07d 100644
--- a/algo/src/main/java/org/neo4j/gds/topologicalsort/TopologicalSort.java
+++ b/algo/src/main/java/org/neo4j/gds/topologicalsort/TopologicalSort.java
@@ -23,8 +23,8 @@
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.collections.haa.HugeAtomicLongArray;
+import org.neo4j.gds.core.concurrency.ExecutorServiceUtil;
import org.neo4j.gds.core.concurrency.ParallelUtil;
-import org.neo4j.gds.core.concurrency.Pools;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.ParalleLongPageCreator;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -98,7 +98,7 @@ private void initializeInDegrees() {
}
private void traverse() {
- ForkJoinPool forkJoinPool = Pools.createForkJoinPool(concurrency);
+ ForkJoinPool forkJoinPool = ExecutorServiceUtil.createForkJoinPool(concurrency);
var tasks = ConcurrentHashMap.>newKeySet();
ParallelUtil.parallelForEachNode(nodeCount, concurrency, TerminationFlag.RUNNING_TRUE, nodeId -> {
diff --git a/algo/src/main/java/org/neo4j/gds/traversal/RandomWalk.java b/algo/src/main/java/org/neo4j/gds/traversal/RandomWalk.java
index fa93cf218e2..2a6bd961037 100644
--- a/algo/src/main/java/org/neo4j/gds/traversal/RandomWalk.java
+++ b/algo/src/main/java/org/neo4j/gds/traversal/RandomWalk.java
@@ -22,7 +22,7 @@
import org.neo4j.gds.Algorithm;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.config.SourceNodesConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.ExecutorServiceUtil;
import org.neo4j.gds.core.concurrency.RunWithConcurrency;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -150,7 +150,7 @@ private void startWalkers(
TOMB,
terminationFlag
),
- Pools.DEFAULT_SINGLE_THREAD_POOL
+ ExecutorServiceUtil.DEFAULT_SINGLE_THREAD_POOL
).whenComplete((__, ___) -> {
progressTracker.endSubTask("RandomWalk");
});
diff --git a/algo/src/main/java/org/neo4j/gds/traversal/RandomWalkAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/traversal/RandomWalkAlgorithmFactory.java
index 831f7f3d860..39637f4ee02 100644
--- a/algo/src/main/java/org/neo4j/gds/traversal/RandomWalkAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/traversal/RandomWalkAlgorithmFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -45,7 +45,7 @@ public RandomWalk build(
RandomWalkBaseConfig configuration,
ProgressTracker progressTracker
) {
- return RandomWalk.create(graph, configuration, progressTracker, Pools.DEFAULT);
+ return RandomWalk.create(graph, configuration, progressTracker, DefaultPool.INSTANCE);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/triangle/IntersectingTriangleCountFactory.java b/algo/src/main/java/org/neo4j/gds/triangle/IntersectingTriangleCountFactory.java
index f76deba421b..4622d95cc86 100644
--- a/algo/src/main/java/org/neo4j/gds/triangle/IntersectingTriangleCountFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/triangle/IntersectingTriangleCountFactory.java
@@ -23,7 +23,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.collections.haa.HugeAtomicLongArray;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -48,7 +48,7 @@ public IntersectingTriangleCount build(
return IntersectingTriangleCount.create(
graph,
configuration,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/triangle/LocalClusteringCoefficientMutateConfig.java b/algo/src/main/java/org/neo4j/gds/triangle/LocalClusteringCoefficientMutateConfig.java
index 0ac7da99813..541b2637c80 100644
--- a/algo/src/main/java/org/neo4j/gds/triangle/LocalClusteringCoefficientMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/triangle/LocalClusteringCoefficientMutateConfig.java
@@ -21,13 +21,14 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface LocalClusteringCoefficientMutateConfig extends LocalClusteringCoefficientBaseConfig, MutatePropertyConfig {
+public interface LocalClusteringCoefficientMutateConfig extends LocalClusteringCoefficientBaseConfig,
+ MutateNodePropertyConfig {
static LocalClusteringCoefficientMutateConfig of(CypherMapWrapper userInput) {
return new LocalClusteringCoefficientMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/triangle/TriangleCountMutateConfig.java b/algo/src/main/java/org/neo4j/gds/triangle/TriangleCountMutateConfig.java
index b47c567ea74..b0371c48413 100644
--- a/algo/src/main/java/org/neo4j/gds/triangle/TriangleCountMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/triangle/TriangleCountMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface TriangleCountMutateConfig extends TriangleCountBaseConfig, MutatePropertyConfig {
+public interface TriangleCountMutateConfig extends TriangleCountBaseConfig, MutateNodePropertyConfig {
static TriangleCountMutateConfig of(CypherMapWrapper userInput) {
return new TriangleCountMutateConfigImpl(userInput);
diff --git a/algo/src/main/java/org/neo4j/gds/triangle/TriangleStreamFactory.java b/algo/src/main/java/org/neo4j/gds/triangle/TriangleStreamFactory.java
index 83a9692f4c4..1c07b8b17c5 100644
--- a/algo/src/main/java/org/neo4j/gds/triangle/TriangleStreamFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/triangle/TriangleStreamFactory.java
@@ -21,7 +21,7 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
public class TriangleStreamFactory extends GraphAlgorithmFactory {
@@ -33,6 +33,6 @@ public String taskName() {
@Override
public TriangleStream build(Graph graph, TriangleCountBaseConfig configuration, ProgressTracker progressTracker) {
- return TriangleStream.create(graph, Pools.DEFAULT, configuration.concurrency());
+ return TriangleStream.create(graph, DefaultPool.INSTANCE, configuration.concurrency());
}
}
diff --git a/algo/src/main/java/org/neo4j/gds/triangle/intersect/GraphIntersect.java b/algo/src/main/java/org/neo4j/gds/triangle/intersect/GraphIntersect.java
index bd83ac7bdac..59b15d4f414 100644
--- a/algo/src/main/java/org/neo4j/gds/triangle/intersect/GraphIntersect.java
+++ b/algo/src/main/java/org/neo4j/gds/triangle/intersect/GraphIntersect.java
@@ -68,8 +68,7 @@ public void intersectAll(long nodeA, IntersectionConsumer consumer) {
// iterates over neighbours of A
CURSOR neighboursA = cacheA;
- // current neighbour of A
- long nodeCFromA = NOT_FOUND;
+
// iterates over neighbours of B
CURSOR neighboursB = cacheB;
// current neighbour of B
@@ -86,7 +85,12 @@ public void intersectAll(long nodeA, IntersectionConsumer consumer) {
// check the second node's degree
int degreeB = degree(nodeB);
if (degreeFilter.test(degreeB)) {
- neighboursB = cursorForNode(neighboursB, nodeB, degreeB);
+ neighboursB = cursorForNode(
+ neighboursB,
+ nodeB,
+ degreeB
+ );
+
// find first neighbour Cb of B with id > B
nodeCFromB = neighboursB.skipUntil(nodeB);
@@ -95,6 +99,8 @@ public void intersectAll(long nodeA, IntersectionConsumer consumer) {
// copy the state of A's cursor
neighboursA = copyCursor(neighboursAMain, neighboursA);
+ var nodeCFromA = NOT_FOUND; //current neighbor from a
+
if (degreeFilter.test(degree(nodeCFromB))) {
// find the first neighbour Ca of A with id >= Cb
nodeCFromA = neighboursA.advance(nodeCFromB);
diff --git a/algo/src/main/java/org/neo4j/gds/undirected/ToUndirectedAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/undirected/ToUndirectedAlgorithmFactory.java
index e3ace5ed1ac..ce858c0903a 100644
--- a/algo/src/main/java/org/neo4j/gds/undirected/ToUndirectedAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/undirected/ToUndirectedAlgorithmFactory.java
@@ -22,7 +22,7 @@
import org.neo4j.gds.GraphStoreAlgorithmFactory;
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.GraphStore;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.AdjacencyListBehavior;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
@@ -39,7 +39,7 @@ public ToUndirected build(
ToUndirectedConfig configuration,
ProgressTracker progressTracker
) {
- return new ToUndirected(graphStore, configuration, progressTracker, Pools.DEFAULT);
+ return new ToUndirected(graphStore, configuration, progressTracker, DefaultPool.INSTANCE);
}
@Override
diff --git a/algo/src/main/java/org/neo4j/gds/walking/CollapsePathAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/walking/CollapsePathAlgorithmFactory.java
index fbb5471a1fd..da8284beb3d 100644
--- a/algo/src/main/java/org/neo4j/gds/walking/CollapsePathAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/walking/CollapsePathAlgorithmFactory.java
@@ -24,7 +24,7 @@
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.GraphStore;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import java.util.Collection;
@@ -66,7 +66,7 @@ public CollapsePath build(
config.allowSelfLoops(),
RelationshipType.of(config.mutateRelationshipType()),
config.concurrency(),
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
}
diff --git a/algo/src/main/java/org/neo4j/gds/wcc/WccAlgorithmFactory.java b/algo/src/main/java/org/neo4j/gds/wcc/WccAlgorithmFactory.java
index 12452cfa332..130ae57ecce 100644
--- a/algo/src/main/java/org/neo4j/gds/wcc/WccAlgorithmFactory.java
+++ b/algo/src/main/java/org/neo4j/gds/wcc/WccAlgorithmFactory.java
@@ -21,8 +21,8 @@
import org.neo4j.gds.GraphAlgorithmFactory;
import org.neo4j.gds.api.Graph;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.concurrency.ParallelUtil;
-import org.neo4j.gds.core.concurrency.Pools;
import org.neo4j.gds.core.utils.mem.MemoryEstimation;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
@@ -50,7 +50,7 @@ public Wcc build(
}
return new Wcc(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ParallelUtil.DEFAULT_BATCH_SIZE,
configuration,
progressTracker
diff --git a/algo/src/main/java/org/neo4j/gds/wcc/WccMutateConfig.java b/algo/src/main/java/org/neo4j/gds/wcc/WccMutateConfig.java
index ed7781ffd5e..24be870b966 100644
--- a/algo/src/main/java/org/neo4j/gds/wcc/WccMutateConfig.java
+++ b/algo/src/main/java/org/neo4j/gds/wcc/WccMutateConfig.java
@@ -21,13 +21,13 @@
import org.neo4j.gds.annotation.Configuration;
import org.neo4j.gds.annotation.ValueClass;
-import org.neo4j.gds.config.MutatePropertyConfig;
+import org.neo4j.gds.config.MutateNodePropertyConfig;
import org.neo4j.gds.core.CypherMapWrapper;
@ValueClass
@Configuration
@SuppressWarnings("immutables:subtype")
-public interface WccMutateConfig extends WccBaseConfig, MutatePropertyConfig {
+public interface WccMutateConfig extends WccBaseConfig, MutateNodePropertyConfig {
static WccMutateConfig of(CypherMapWrapper userInput) {
return new WccMutateConfigImpl(userInput);
diff --git a/algo/src/test/java/org/neo4j/gds/allshortestpaths/MSBFSAllShortestPathsTest.java b/algo/src/test/java/org/neo4j/gds/allshortestpaths/MSBFSAllShortestPathsTest.java
index c12834b6ba3..4a817d7be80 100644
--- a/algo/src/test/java/org/neo4j/gds/allshortestpaths/MSBFSAllShortestPathsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/allshortestpaths/MSBFSAllShortestPathsTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.StoreLoaderBuilder;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.config.ConcurrencyConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.graphbuilder.GraphBuilder;
import static org.junit.jupiter.api.Assertions.fail;
@@ -76,7 +76,7 @@ void testResults() {
.addRelationshipType(RELATIONSHIP)
.build()
.graph();
- testASP(new MSBFSAllShortestPaths(graph, ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT));
+ testASP(new MSBFSAllShortestPaths(graph, ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE));
}
private void testASP(final MSBFSASPAlgorithm hugeMSBFSAllShortestPaths) {
diff --git a/algo/src/test/java/org/neo4j/gds/allshortestpaths/WeightedAllShortestPathsTest.java b/algo/src/test/java/org/neo4j/gds/allshortestpaths/WeightedAllShortestPathsTest.java
index 3a58d13e787..53defe79ee9 100644
--- a/algo/src/test/java/org/neo4j/gds/allshortestpaths/WeightedAllShortestPathsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/allshortestpaths/WeightedAllShortestPathsTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.PropertyMapping;
import org.neo4j.gds.StoreLoaderBuilder;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.graphbuilder.GraphBuilder;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -88,7 +88,7 @@ void testResults() {
final ResultConsumer mock = mock(ResultConsumer.class);
- new WeightedAllShortestPaths(graph, Pools.DEFAULT, 4)
+ new WeightedAllShortestPaths(graph, DefaultPool.INSTANCE, 4)
.compute()
.forEach(r -> {
assertNotEquals(Double.POSITIVE_INFINITY, r.distance);
@@ -115,7 +115,7 @@ void shouldThrowIfGraphHasNoRelationshipProperty() {
.graph();
UnsupportedOperationException exception = assertThrows(UnsupportedOperationException.class, () -> {
- new WeightedAllShortestPaths(graph, Pools.DEFAULT, 4);
+ new WeightedAllShortestPaths(graph, DefaultPool.INSTANCE, 4);
});
assertTrue(exception.getMessage().contains("not supported"));
diff --git a/algo/src/test/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutTest.java b/algo/src/test/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutTest.java
index 397ac21f29e..8a9b33b6b20 100644
--- a/algo/src/test/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutTest.java
+++ b/algo/src/test/java/org/neo4j/gds/approxmaxkcut/ApproxMaxKCutTest.java
@@ -28,7 +28,7 @@
import org.neo4j.gds.collections.haa.HugeAtomicDoubleArray;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.paged.HugeByteArray;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
@@ -172,7 +172,7 @@ void computeCorrectResults(
var graph = minimize ? minGraph : maxGraph;
var approxMaxKCut = new ApproxMaxKCut(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
@@ -214,7 +214,7 @@ void respectMinCommunitySizes(int concurrency) {
var approxMaxKCut = new ApproxMaxKCut(
maxGraph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/betweenness/BetweennessCentralityTest.java b/algo/src/test/java/org/neo4j/gds/betweenness/BetweennessCentralityTest.java
index 161554b0ec3..dee1368f0c6 100644
--- a/algo/src/test/java/org/neo4j/gds/betweenness/BetweennessCentralityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/betweenness/BetweennessCentralityTest.java
@@ -29,7 +29,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -141,7 +141,7 @@ void sampling(int concurrency, TestGraph graph, int samplingSize, Map selectionStrategy.next())).containsExactly(
graph.toMappedNodeId("a"),
@@ -107,9 +107,9 @@ void neverIncludeZeroDegNodesIfBetterChoicesExist() {
TestGraph graph = fromGdl("(), (), (), (), (), (a)-->(), (), (), ()");
SelectionStrategy selectionStrategy = new RandomDegreeSelectionStrategy(1);
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
assertEquals(1, samplingSize(selectionStrategy));
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
assertEquals(graph.toMappedNodeId("a"), selectionStrategy.next());
}
@@ -118,18 +118,18 @@ void not100PercentLikelyUnlessMaxDegNode() {
TestGraph graph = fromGdl("(a)-->(b), (b)-->(c), (b)-->(d)");
SelectionStrategy selectionStrategy = new RandomDegreeSelectionStrategy(1, Optional.of(42L));
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
assertEquals(1, samplingSize(selectionStrategy));
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
assertEquals(graph.toMappedNodeId("b"), selectionStrategy.next());
}
@Test
void selectHighDegreeNode() {
SelectionStrategy selectionStrategy = new RandomDegreeSelectionStrategy(1);
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
assertEquals(1, samplingSize(selectionStrategy));
- selectionStrategy.init(graph, Pools.DEFAULT, 1);
+ selectionStrategy.init(graph, DefaultPool.INSTANCE, 1);
var isA = selectionStrategy.next();
var isB = selectionStrategy.next();
assertTrue(isA != SelectionStrategy.NONE_SELECTED || isB != SelectionStrategy.NONE_SELECTED);
diff --git a/algo/src/test/java/org/neo4j/gds/betweenness/WeightedBetweennessCentralityTest.java b/algo/src/test/java/org/neo4j/gds/betweenness/WeightedBetweennessCentralityTest.java
index f7a7a33f86c..6b1d8db1526 100644
--- a/algo/src/test/java/org/neo4j/gds/betweenness/WeightedBetweennessCentralityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/betweenness/WeightedBetweennessCentralityTest.java
@@ -26,7 +26,7 @@
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -86,7 +86,7 @@ void shouldEqualWithUnweightedWhenWeightsAreEqual() {
equallyWeightedGraph,
new RandomDegreeSelectionStrategy(7, Optional.of(42L)),
ForwardTraverser.Factory.weighted(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
8,
ProgressTracker.NULL_TRACKER
);
@@ -94,7 +94,7 @@ void shouldEqualWithUnweightedWhenWeightsAreEqual() {
equallyWeightedGraph,
new RandomDegreeSelectionStrategy(7, Optional.of(42L)),
ForwardTraverser.Factory.unweighted(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
8,
ProgressTracker.NULL_TRACKER
);
@@ -119,7 +119,7 @@ void shouldComputeWithWeights() {
weightedGraph,
new RandomDegreeSelectionStrategy(7, Optional.of(42L)),
ForwardTraverser.Factory.weighted(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
8,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDirectedTest.java b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDirectedTest.java
index 2b24a33c676..df826b3294b 100644
--- a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDirectedTest.java
+++ b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDirectedTest.java
@@ -20,7 +20,7 @@
package org.neo4j.gds.closeness;
import org.junit.jupiter.api.Test;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -88,7 +88,7 @@ void testCentrality() {
var algo = ClosenessCentrality.of(
graph,
ImmutableClosenessCentralityStreamConfig.builder().build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -108,7 +108,7 @@ void testCentralityWithWassermanFaust() {
var algo = ClosenessCentrality.of(
graph,
ImmutableClosenessCentralityStreamConfig.builder().useWassermanFaust(true).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDiscoTest.java b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDiscoTest.java
index 2a0fb88d9d6..c2256052152 100644
--- a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDiscoTest.java
+++ b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityDiscoTest.java
@@ -22,7 +22,7 @@
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -67,7 +67,7 @@ void testHuge() {
var algo = ClosenessCentrality.of(
graph,
ImmutableClosenessCentralityStreamConfig.builder().concurrency(2).useWassermanFaust(true).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityTest.java b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityTest.java
index 46702494f6d..eaa49008d1f 100644
--- a/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/closeness/ClosenessCentralityTest.java
@@ -23,7 +23,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.TestProgressTracker;
import org.neo4j.gds.compat.Neo4jProxy;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -93,7 +93,7 @@ void testGetCentrality() {
var algo = ClosenessCentrality.of(
graph,
ImmutableClosenessCentralityStreamConfig.builder().build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -116,7 +116,7 @@ void shouldLogProgress() {
var algo = ClosenessCentrality.of(
graph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
diff --git a/algo/src/test/java/org/neo4j/gds/conductance/ConductanceTest.java b/algo/src/test/java/org/neo4j/gds/conductance/ConductanceTest.java
index 3e8ca895100..a5045d4cd22 100644
--- a/algo/src/test/java/org/neo4j/gds/conductance/ConductanceTest.java
+++ b/algo/src/test/java/org/neo4j/gds/conductance/ConductanceTest.java
@@ -28,7 +28,7 @@
import org.neo4j.gds.TestSupport;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.TaskProgressTracker;
@@ -134,7 +134,7 @@ void computeCorrectResults(
var conductance = new Conductance(
orientation == Orientation.NATURAL ? naturalGraph : undirectedGraph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/degree/DegreeCentralityTest.java b/algo/src/test/java/org/neo4j/gds/degree/DegreeCentralityTest.java
index bb38b51b23b..e3f795a479f 100644
--- a/algo/src/test/java/org/neo4j/gds/degree/DegreeCentralityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/degree/DegreeCentralityTest.java
@@ -28,7 +28,7 @@
import org.neo4j.gds.TestProgressTracker;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
@@ -148,7 +148,7 @@ void shouldComputeCorrectResults(boolean weighted, Orientation orientation, Map<
var degreeCentrality = new DegreeCentrality(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
@@ -200,7 +200,7 @@ void testProgressLogging(boolean weighted) {
var progressTracker = new TestProgressTracker(progressTask, log, 1, EmptyTaskRegistryFactory.INSTANCE);
var degreeCentrality = new DegreeCentrality(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
progressTracker
);
@@ -225,7 +225,7 @@ void shouldSupportAllOrientations(Orientation orientation) {
var degreeCentrality = new DegreeCentrality(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
config,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/fastrp/FastRPTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/fastrp/FastRPTest.java
index 451e7ff643b..2d549b3b577 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/fastrp/FastRPTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/fastrp/FastRPTest.java
@@ -31,7 +31,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.ArrayIdMap;
import org.neo4j.gds.core.loading.LabelInformationBuilders;
import org.neo4j.gds.core.loading.construction.GraphFactory;
@@ -626,7 +626,7 @@ void shouldBeDeterministicGivenSameOriginalIds() {
.nodes(firstIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var secondMappedToOriginal = HugeLongArray.newArray(nodeCount);
@@ -650,7 +650,7 @@ void shouldBeDeterministicGivenSameOriginalIds() {
.nodes(secondIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var random = new SplittableRandom(42);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageEmbeddingsGeneratorTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageEmbeddingsGeneratorTest.java
index 5cfed409328..a1b4fe0032d 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageEmbeddingsGeneratorTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageEmbeddingsGeneratorTest.java
@@ -24,7 +24,7 @@
import org.junit.jupiter.params.provider.EnumSource;
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.CSRGraphStore;
import org.neo4j.gds.core.utils.paged.HugeObjectArray;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -74,7 +74,7 @@ void makesEmbeddings(Aggregator.AggregatorType aggregatorType) {
var features = GraphSageHelper.initializeSingleLabelFeatures(weightedGraph, config);
- var trainModel = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainModel = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
GraphSageModelTrainer.ModelTrainResult result = trainModel.train(weightedGraph, features);
@@ -84,7 +84,7 @@ void makesEmbeddings(Aggregator.AggregatorType aggregatorType) {
config.concurrency(),
new SingleLabelFeatureFunction(),
config.randomSeed(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -112,7 +112,7 @@ void makesEmbeddingsFromMultiLabelModel(Aggregator.AggregatorType aggregatorType
var trainer = new MultiLabelGraphSageTrain(
weightedGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -125,7 +125,7 @@ void makesEmbeddingsFromMultiLabelModel(Aggregator.AggregatorType aggregatorType
config.concurrency(),
model.data().featureFunction(),
model.trainConfig().randomSeed(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -167,7 +167,7 @@ void embeddingsForNodeFilteredGraph() {
var trainer = new SingleLabelGraphSageTrain(
filteredGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -180,7 +180,7 @@ void embeddingsForNodeFilteredGraph() {
config.concurrency(),
model.data().featureFunction(),
model.trainConfig().randomSeed(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageModelTrainerTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageModelTrainerTest.java
index 71fb4e5276e..93c3cdc0221 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageModelTrainerTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageModelTrainerTest.java
@@ -34,7 +34,7 @@
import org.neo4j.gds.beta.generator.PropertyProducer;
import org.neo4j.gds.beta.generator.RandomGraphGenerator;
import org.neo4j.gds.beta.generator.RelationshipDistribution;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.HugeObjectArray;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.embeddings.graphsage.algo.GraphSageTrainConfigImpl;
@@ -120,7 +120,7 @@ void trainsWithRelationshipWeight(AggregatorType aggregatorType) {
.modelUser("")
.build();
- var trainModel = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainModel = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
int nodeCount = 5_000;
var bigGraph = RandomGraphGenerator
@@ -160,7 +160,7 @@ void trainsWithMeanAggregator(boolean useRelationshipWeight) {
.modelName(MODEL_NAME)
.build();
- var trainModel = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainModel = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
var maybeWeights = useRelationshipWeight ? Optional.of("times") : Optional.empty();
@@ -201,7 +201,7 @@ void trainsWithPoolAggregator(boolean useRelationshipWeight) {
.modelName(MODEL_NAME)
.build();
- var trainModel = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainModel = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
GraphSageModelTrainer.ModelTrainResult result = trainModel.train(graph, features);
Layer[] layers = result.layers();
@@ -251,7 +251,7 @@ void shouldTrainModelWithArrayProperties() {
.modelUser("")
.build();
- var trainer = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainer = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
var result = trainer.train(arrayGraph, arrayFeatures);
@@ -276,7 +276,7 @@ void testLosses() {
var trainer = new GraphSageModelTrainer(
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -309,7 +309,7 @@ void testLossesWithPoolAggregator() {
var trainer = new GraphSageModelTrainer(
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -329,7 +329,7 @@ void testLossesWithPoolAggregator() {
void testConvergence() {
var trainer = new GraphSageModelTrainer(
configBuilder.modelName("convergingModel:)").tolerance(100.0).epochs(10).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -355,13 +355,13 @@ void batchesPerIteration() {
var trainResultWithoutSampling = new GraphSageModelTrainer(
configBuilder.maybeBatchSamplingRatio(1.0).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).train(unweightedGraph, features);
var trainResultWithSampling = new GraphSageModelTrainer(
configBuilder.maybeBatchSamplingRatio(0.01).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).train(unweightedGraph, features);
@@ -386,7 +386,7 @@ void l2Penalty(double penalty, double expectedLoss) {
var result = new GraphSageModelTrainer(
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).train(unweightedGraph, features);
@@ -404,8 +404,8 @@ void seededSingleBatch(long seed) {
.concurrency(1)
.build();
- var trainer = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
- var otherTrainer = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainer = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
+ var otherTrainer = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
var result = trainer.train(unweightedGraph, features);
var otherResult = otherTrainer.train(unweightedGraph, features);
@@ -424,8 +424,8 @@ void seededMultiBatch(long seed) {
.batchSize(5)
.build();
- var trainer = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
- var otherTrainer = new GraphSageModelTrainer(config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var trainer = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
+ var otherTrainer = new GraphSageModelTrainer(config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
var result = trainer.train(unweightedGraph, features);
var otherResult = otherTrainer.train(unweightedGraph, features);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageTest.java
index a201bb9f114..eb6f3cd9b89 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/GraphSageTest.java
@@ -35,7 +35,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.config.RandomGraphGeneratorConfig;
import org.neo4j.gds.core.Aggregation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.huge.HugeGraph;
import org.neo4j.gds.core.loading.CSRGraphStoreUtil;
import org.neo4j.gds.core.loading.construction.NodeLabelTokens;
@@ -146,7 +146,7 @@ void shouldNotMakeNanEmbeddings(Aggregator.AggregatorType aggregator) {
var trainAlgo = new SingleLabelGraphSageTrain(
orphanGraph,
trainConfig,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -180,7 +180,7 @@ void differentTrainAndPredictionGraph() {
.concurrency(1)
.build();
- var graphSageTrain = new SingleLabelGraphSageTrain(graph, trainConfig, Pools.DEFAULT, ProgressTracker.NULL_TRACKER, testGdsVersion);
+ var graphSageTrain = new SingleLabelGraphSageTrain(graph, trainConfig, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER, testGdsVersion);
var model = graphSageTrain.compute();
@@ -205,7 +205,7 @@ void differentTrainAndPredictionGraph() {
.batchSize(2)
.build();
- var graphSage = new GraphSage(trainGraph, model, streamConfig, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var graphSage = new GraphSage(trainGraph, model, streamConfig, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
assertThat(graphSage.compute().embeddings().size()).isEqualTo(predictNodeCount);
}
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/algo/MultiLabelGraphSageTrainTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/algo/MultiLabelGraphSageTrainTest.java
index b4c98ffb212..58aac3b66b2 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/algo/MultiLabelGraphSageTrainTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/graphsage/algo/MultiLabelGraphSageTrainTest.java
@@ -24,7 +24,7 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.embeddings.graphsage.ActivationFunction;
import org.neo4j.gds.embeddings.graphsage.Aggregator;
@@ -98,7 +98,7 @@ void shouldRunWithDifferentProjectedFeatureSizes(String name, GraphSageTrainConf
var multiLabelGraphSageTrain = new MultiLabelGraphSageTrain(
weightedGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -119,7 +119,7 @@ void shouldStoreMultiLabelFeatureFunctionInModel() {
var multiLabelGraphSageTrain = new MultiLabelGraphSageTrain(
weightedGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -148,7 +148,7 @@ void runsTrainingOnMultiLabelGraph() {
var graphSageTrain = new MultiLabelGraphSageTrain(
weightedGraph,
graphSageTrainConfig,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -191,7 +191,7 @@ void shouldFailUnequalLengthArrays() {
var multiLabelGraphSageTrain = new MultiLabelGraphSageTrain(
unequalGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
@@ -216,7 +216,7 @@ void shouldFailMissingArrayProperty(Graph graph, String property, long missingNo
var multiLabelGraphSageTrain = new MultiLabelGraphSageTrain(
graph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER,
testGdsVersion
);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/hashgnn/HashGNNTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/hashgnn/HashGNNTest.java
index a2e414e07b8..e830ae44650 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/hashgnn/HashGNNTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/hashgnn/HashGNNTest.java
@@ -36,7 +36,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.GraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.ArrayIdMap;
import org.neo4j.gds.core.loading.LabelInformationBuilders;
import org.neo4j.gds.core.loading.construction.GraphFactory;
@@ -422,7 +422,7 @@ void shouldBeDeterministicGivenSameOriginalIds() {
.nodes(firstIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var secondMappedToOriginal = HugeLongArray.newArray(nodeCount);
@@ -446,7 +446,7 @@ void shouldBeDeterministicGivenSameOriginalIds() {
.nodes(secondIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var random = new SplittableRandom(42);
diff --git a/algo/src/test/java/org/neo4j/gds/embeddings/node2vec/Node2VecTest.java b/algo/src/test/java/org/neo4j/gds/embeddings/node2vec/Node2VecTest.java
index 06712e2221c..8b4ede616d6 100644
--- a/algo/src/test/java/org/neo4j/gds/embeddings/node2vec/Node2VecTest.java
+++ b/algo/src/test/java/org/neo4j/gds/embeddings/node2vec/Node2VecTest.java
@@ -44,7 +44,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.GraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.ArrayIdMap;
import org.neo4j.gds.core.loading.LabelInformationBuilders;
import org.neo4j.gds.core.loading.construction.GraphFactory;
@@ -280,7 +280,7 @@ void shouldBeFairlyConsistentUnderOriginalIds(EmbeddingInitializer embeddingInit
.nodes(firstIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var secondMappedToOriginal = HugeLongArray.newArray(nodeCount);
@@ -302,7 +302,7 @@ void shouldBeFairlyConsistentUnderOriginalIds(EmbeddingInitializer embeddingInit
.nodes(secondIdMap)
.relationshipType(RelationshipType.of("REL"))
.orientation(Orientation.UNDIRECTED)
- .executorService(Pools.DEFAULT)
+ .executorService(DefaultPool.INSTANCE)
.build();
var random = new SplittableRandom(42);
diff --git a/algo/src/test/java/org/neo4j/gds/harmonic/HarmonicCentralityTest.java b/algo/src/test/java/org/neo4j/gds/harmonic/HarmonicCentralityTest.java
index d1129e9da9d..99009e5bb62 100644
--- a/algo/src/test/java/org/neo4j/gds/harmonic/HarmonicCentralityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/harmonic/HarmonicCentralityTest.java
@@ -24,7 +24,7 @@
import org.neo4j.gds.TestProgressTracker;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.compat.Neo4jProxy;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Tasks;
@@ -67,7 +67,7 @@ void shouldComputeHarmonicCentrality() {
var harmonicCentrality = new HarmonicCentrality(
graph,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -89,7 +89,7 @@ void testLogging() {
var algo = new HarmonicCentrality(
graph,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
diff --git a/algo/src/test/java/org/neo4j/gds/indexInverse/InverseRelationshipsTest.java b/algo/src/test/java/org/neo4j/gds/indexInverse/InverseRelationshipsTest.java
index a5f46a2c531..9e17be857dd 100644
--- a/algo/src/test/java/org/neo4j/gds/indexInverse/InverseRelationshipsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/indexInverse/InverseRelationshipsTest.java
@@ -27,7 +27,7 @@
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.GraphStore;
import org.neo4j.gds.compat.Neo4jProxy;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -79,7 +79,7 @@ void shouldCreateIndexedRelationships(int concurrency) {
graphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
assertThat(inverseRelationshipsPerType).hasSize(1);
@@ -110,7 +110,7 @@ void shouldIndexMultipleTypes(Object relTypes) {
graphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
assertThat(inverseRelationshipsPerType).hasSize(internalTypes.size());
diff --git a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnConnectedGraphTest.java b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnConnectedGraphTest.java
index e406cadefdb..7125941382f 100644
--- a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnConnectedGraphTest.java
+++ b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnConnectedGraphTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.Orientation;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.TaskProgressTracker;
@@ -99,7 +99,7 @@ void testSpreadWithSeed1() {
// gain[d|a,b,d,e] : 0 {a already activates d} 1(d) 1(d) = 2/3 =0.667
IdFunction idFunction = variable -> graph.toMappedNodeId(variable);
- CELF celf = new CELF(graph, 5, 0.2, 3, Pools.DEFAULT, 2, 0, DEFAULT_BATCH_SIZE,
+ CELF celf = new CELF(graph, 5, 0.2, 3, DefaultPool.INSTANCE, 2, 0, DEFAULT_BATCH_SIZE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
var celfResult = celf.compute();
diff --git a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnTreeGraphTest.java b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnTreeGraphTest.java
index 6831373860b..43198fb6275 100644
--- a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnTreeGraphTest.java
+++ b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CELFOnTreeGraphTest.java
@@ -24,7 +24,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -136,7 +136,7 @@ void testSpreadWithSeed1() {
5,
0.51,
3,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
1,
10,
DEFAULT_BATCH_SIZE,
diff --git a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CelfTest.java b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CelfTest.java
index 282613cd08b..80e7254bdcc 100644
--- a/algo/src/test/java/org/neo4j/gds/influenceMaximization/CelfTest.java
+++ b/algo/src/test/java/org/neo4j/gds/influenceMaximization/CelfTest.java
@@ -24,7 +24,7 @@
import org.neo4j.gds.api.schema.Direction;
import org.neo4j.gds.beta.generator.RandomGraphGenerator;
import org.neo4j.gds.beta.generator.RelationshipDistribution;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import static org.assertj.core.api.Assertions.assertThat;
@@ -44,7 +44,7 @@ void shouldNotReturnNegativeGains(int seedSize) {
.build()
.generate();
- var celf = new CELF(graph, seedSize, 0.1, 3, Pools.DEFAULT, 1, 10, 5, ProgressTracker.NULL_TRACKER).compute();
+ var celf = new CELF(graph, seedSize, 0.1, 3, DefaultPool.INSTANCE, 1, 10, 5, ProgressTracker.NULL_TRACKER).compute();
for (var a : celf) {
assertThat(a.value).isNotNegative();
}
diff --git a/algo/src/test/java/org/neo4j/gds/k1coloring/K1ColoringTest.java b/algo/src/test/java/org/neo4j/gds/k1coloring/K1ColoringTest.java
index 252cdff3b0a..121bd5ca2a9 100644
--- a/algo/src/test/java/org/neo4j/gds/k1coloring/K1ColoringTest.java
+++ b/algo/src/test/java/org/neo4j/gds/k1coloring/K1ColoringTest.java
@@ -32,7 +32,7 @@
import org.neo4j.gds.core.Aggregation;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -69,7 +69,7 @@ void testK1Coloring() {
1000,
DEFAULT_BATCH_SIZE,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -110,7 +110,7 @@ void testParallelK1Coloring() {
100,
DEFAULT_BATCH_SIZE,
8,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -177,7 +177,7 @@ void everyNodeShouldHaveBeenColored() {
100,
DEFAULT_BATCH_SIZE,
8,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -214,7 +214,7 @@ void shouldLogProgress(){
config.maxIterations(),
DEFAULT_BATCH_SIZE,
config.concurrency(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
);
diff --git a/algo/src/test/java/org/neo4j/gds/kcore/KCoreDecompositionTest.java b/algo/src/test/java/org/neo4j/gds/kcore/KCoreDecompositionTest.java
index decaeeac217..5f7d54f6c72 100644
--- a/algo/src/test/java/org/neo4j/gds/kcore/KCoreDecompositionTest.java
+++ b/algo/src/test/java/org/neo4j/gds/kcore/KCoreDecompositionTest.java
@@ -215,4 +215,37 @@ void shouldComputeCoreDecomposition() {
}
}
+
+ @GdlExtension
+ @Nested
+ class K4Graph {
+ @GdlGraph(orientation = Orientation.UNDIRECTED)
+ private static final String DB_CYPHER =
+ "CREATE " +
+ " (a:node)," +
+ " (b:node)," +
+ " (c:node)," +
+ " (d:node)," +
+
+ "(a)-[:R]->(b)," +
+ "(a)-[:R]->(c)," +
+ "(a)-[:R]->(d)," +
+ "(b)-[:R]->(c)," +
+ "(b)-[:R]->(d)," +
+ "(c)-[:R]->(d)";
+
+
+ @Inject
+ TestGraph graph;
+
+ @Test
+ void shouldAdvanceScanningDegreeCorrectly() {
+ var kcore = new KCoreDecomposition(graph, 1, ProgressTracker.NULL_TRACKER, 1).compute();
+ assertThat(kcore.degeneracy()).isEqualTo(3);
+ var coreValues = kcore.coreValues();
+
+ assertThat(coreValues.toArray()).isEqualTo(new int[]{3, 3, 3, 3});
+
+ }
+ }
}
diff --git a/algo/src/test/java/org/neo4j/gds/kspanningtree/KSpanningTreeTest.java b/algo/src/test/java/org/neo4j/gds/kspanningtree/KSpanningTreeTest.java
index d41b8d5874f..301f6c95cc6 100644
--- a/algo/src/test/java/org/neo4j/gds/kspanningtree/KSpanningTreeTest.java
+++ b/algo/src/test/java/org/neo4j/gds/kspanningtree/KSpanningTreeTest.java
@@ -76,14 +76,6 @@ class KSpanningTreeTest {
@Inject
private IdFunction idFunction;
- private static final int OFFSET = 5;
-
- @GdlGraph(idOffset = OFFSET, orientation = Orientation.UNDIRECTED, graphNamePrefix = "offset")
- private static final String DB_CYPHER_WITH_OFFSET = DB_CYPHER;
-
- @Inject
- private Graph offsetGraph;
-
private int a, b, c, d, x;
@BeforeEach
@@ -118,15 +110,6 @@ void testMinimumKSpanningTree() {
assertThat(spanningTree.head(b)).isNotEqualTo(spanningTree.head(x));
}
- @Test
- void testNeoIdsWithOffset() {
- var spanningTree = new KSpanningTree(graph, Prim.MIN_OPERATOR, 0, 2, ProgressTracker.NULL_TRACKER).compute();
- var otherSpanningTree = new KSpanningTree(offsetGraph, Prim.MIN_OPERATOR, OFFSET, 2, ProgressTracker.NULL_TRACKER).compute();
-
- assertThat(spanningTree.parentArray().toArray())
- .containsExactly(otherSpanningTree.parentArray().toArray());
- }
-
@Test
void shouldProduceSingleConnectedTree() {
var factory = GdlFactory.of("CREATE" +
diff --git a/algo/src/test/java/org/neo4j/gds/labelpropagation/LabelPropagationTest.java b/algo/src/test/java/org/neo4j/gds/labelpropagation/LabelPropagationTest.java
index 4c2ead6bfc8..2f60b5a3989 100644
--- a/algo/src/test/java/org/neo4j/gds/labelpropagation/LabelPropagationTest.java
+++ b/algo/src/test/java/org/neo4j/gds/labelpropagation/LabelPropagationTest.java
@@ -29,7 +29,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -83,7 +83,7 @@ void shouldUseOriginalNodeIdWhenSeedPropertyIsMissing() {
LabelPropagation lp = new LabelPropagation(
graph,
ImmutableLabelPropagationStreamConfig.builder().maxIterations(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
assertArrayEquals(
@@ -109,7 +109,7 @@ void shouldUseSeedProperty() {
.seedProperty("seedId")
.maxIterations(1)
.build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -146,7 +146,7 @@ private void testLPClustering(Graph graph, int batchSize) {
LabelPropagation lp = new LabelPropagation(
graph,
DEFAULT_CONFIG,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
lp.withBatchSize(batchSize);
@@ -202,7 +202,7 @@ void shouldLogProgress() {
var lp = new LabelPropagation(
graph,
DEFAULT_CONFIG,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
testTracker
);
diff --git a/algo/src/test/java/org/neo4j/gds/labelpropagation/NonStabilizingLabelPropagationTest.java b/algo/src/test/java/org/neo4j/gds/labelpropagation/NonStabilizingLabelPropagationTest.java
index acfea1e94fb..aa25dc610c9 100644
--- a/algo/src/test/java/org/neo4j/gds/labelpropagation/NonStabilizingLabelPropagationTest.java
+++ b/algo/src/test/java/org/neo4j/gds/labelpropagation/NonStabilizingLabelPropagationTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -62,7 +62,7 @@ void testLabelPropagationDoesStabilize() {
LabelPropagation labelPropagation = new LabelPropagation(
graph,
ImmutableLabelPropagationStreamConfig.builder().build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
LabelPropagationResult compute = labelPropagation.compute();
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/GraphAggregationPhaseTest.java b/algo/src/test/java/org/neo4j/gds/leiden/GraphAggregationPhaseTest.java
index 10b2236fcf8..93cd013212f 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/GraphAggregationPhaseTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/GraphAggregationPhaseTest.java
@@ -22,7 +22,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
import org.neo4j.gds.api.schema.Direction;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.ExecutorServiceUtil;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -79,7 +79,7 @@ void testGraphAggregation() {
Direction.UNDIRECTED,
communities,
1L,
- Pools.DEFAULT_SINGLE_THREAD_POOL,
+ ExecutorServiceUtil.DEFAULT_SINGLE_THREAD_POOL,
4,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/GraphWithSelfLoopTest.java b/algo/src/test/java/org/neo4j/gds/leiden/GraphWithSelfLoopTest.java
index a82da2cf43b..7724f5827e7 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/GraphWithSelfLoopTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/GraphWithSelfLoopTest.java
@@ -23,7 +23,8 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
import org.neo4j.gds.api.schema.Direction;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
+import org.neo4j.gds.core.concurrency.ExecutorServiceUtil;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -70,7 +71,7 @@ void shouldCalculateModularityCorrectly() {
1.0 / graph.relationshipCount(),
1.0 / graph.relationshipCount(),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
@@ -86,7 +87,7 @@ void shouldAggregateCorrectly(){
Direction.UNDIRECTED,
communities,
2L,
- Pools.DEFAULT_SINGLE_THREAD_POOL,
+ ExecutorServiceUtil.DEFAULT_SINGLE_THREAD_POOL,
4,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
@@ -121,7 +122,7 @@ void shouldMaintainPartition() {
Direction.UNDIRECTED,
refinedCommunities,
2,
- Pools.DEFAULT_SINGLE_THREAD_POOL,
+ ExecutorServiceUtil.DEFAULT_SINGLE_THREAD_POOL,
1,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
@@ -164,7 +165,7 @@ void shouldCalculateModularityInSummaryGraph() {
Direction.UNDIRECTED,
localCommunities,
2,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
1,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
@@ -180,7 +181,7 @@ void shouldCalculateModularityInSummaryGraph() {
1.0 / graph.relationshipCount(),
1.0 / graph.relationshipCount(),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/LeidenTest.java b/algo/src/test/java/org/neo4j/gds/leiden/LeidenTest.java
index 2685788beb0..7f1d0c56d85 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/LeidenTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/LeidenTest.java
@@ -30,7 +30,7 @@
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.config.RandomGraphGeneratorConfig;
import org.neo4j.gds.core.Aggregation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.ExecutorServiceUtil;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -219,7 +219,7 @@ void shouldMaintainPartition() {
Direction.UNDIRECTED,
refinedCommunities,
4,
- Pools.DEFAULT_SINGLE_THREAD_POOL,
+ ExecutorServiceUtil.DEFAULT_SINGLE_THREAD_POOL,
1,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/ModularityComputerTest.java b/algo/src/test/java/org/neo4j/gds/leiden/ModularityComputerTest.java
index 9264951ada4..5d11a2e780b 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/ModularityComputerTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/ModularityComputerTest.java
@@ -23,7 +23,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
import org.neo4j.gds.api.schema.Direction;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -83,7 +83,7 @@ void shouldCalculateModularityCorrectly() {
1.0 / graph.relationshipCount(),
1.0 / graph.relationshipCount(),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
assertThat(modularity).isCloseTo(0.4230, Offset.offset(1e-3));
@@ -102,7 +102,7 @@ void shouldCalculateModularityInSummaryGraph() {
Direction.UNDIRECTED,
localCommunities,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
1,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
@@ -116,7 +116,7 @@ void shouldCalculateModularityInSummaryGraph() {
1.0 / graph.relationshipCount(),
1.0 / graph.relationshipCount(),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
assertThat(modularity).isCloseTo(0.4230, Offset.offset(1e-3));
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseKarateTest.java b/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseKarateTest.java
index 89a8ebc17d3..cab2f6b6dcd 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseKarateTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseKarateTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -73,7 +73,7 @@ void testRefinementPhase() {
0.01,
19L,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseTest.java b/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseTest.java
index 2321b3638c9..f9597a50a14 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/RefinementPhaseTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -80,7 +80,7 @@ void shouldRefine() {
0.01,
19L,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
var refinementResult = refinement.run();
diff --git a/algo/src/test/java/org/neo4j/gds/leiden/WeightedModularityComputerTest.java b/algo/src/test/java/org/neo4j/gds/leiden/WeightedModularityComputerTest.java
index 65f3fbd70e4..92de2482424 100644
--- a/algo/src/test/java/org/neo4j/gds/leiden/WeightedModularityComputerTest.java
+++ b/algo/src/test/java/org/neo4j/gds/leiden/WeightedModularityComputerTest.java
@@ -23,7 +23,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
import org.neo4j.gds.api.schema.Direction;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
@@ -84,7 +84,7 @@ void shouldCalculateModularityCorrectly() {
1.0 / (4.0 * graph.relationshipCount()),
1.0 / (4.0 * graph.relationshipCount()),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
assertThat(modularity).isCloseTo(0.4230, Offset.offset(1e-3));
@@ -103,7 +103,7 @@ void shouldCalculateModularityInSummaryGraph() {
Direction.UNDIRECTED,
localCommunities,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
1,
TerminationFlag.RUNNING_TRUE,
ProgressTracker.NULL_TRACKER
@@ -117,7 +117,7 @@ void shouldCalculateModularityInSummaryGraph() {
1.0 / (4 * graph.relationshipCount()),
1.0 / (4 * graph.relationshipCount()),
4,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.EmptyProgressTracker.NULL_TRACKER
);
assertThat(modularity).isCloseTo(0.4230, Offset.offset(1e-3));
diff --git a/algo/src/test/java/org/neo4j/gds/louvain/LouvainTest.java b/algo/src/test/java/org/neo4j/gds/louvain/LouvainTest.java
index 65f52d8f258..db34cff670a 100644
--- a/algo/src/test/java/org/neo4j/gds/louvain/LouvainTest.java
+++ b/algo/src/test/java/org/neo4j/gds/louvain/LouvainTest.java
@@ -36,7 +36,7 @@
import org.neo4j.gds.core.Aggregation;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.huge.HugeGraph;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.mem.MemoryRange;
@@ -155,7 +155,7 @@ void testUnweighted() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -204,7 +204,7 @@ void testWeighted() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -253,7 +253,7 @@ void testSeeded() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -304,7 +304,7 @@ void testTolerance() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -340,7 +340,7 @@ void testMaxLevels() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -457,7 +457,7 @@ void testCanBeInterruptedByTxCancellation() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
louvain.setTerminationFlag(terminationFlag);
@@ -494,7 +494,7 @@ void testLogging() {
config.tolerance(),
config.concurrency(),
progressTracker,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
@@ -522,7 +522,7 @@ void shouldThrowOnNegativeSeed() {
config.tolerance(),
config.concurrency(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
algorithm.setTerminationFlag(TerminationFlag.RUNNING_TRUE);
@@ -554,7 +554,7 @@ void shouldGiveSameResultWithCalculator() {
TOLERANCE_DEFAULT,
4,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var result = louvain.compute();
diff --git a/algo/src/test/java/org/neo4j/gds/modularityoptimization/FootballTest.java b/algo/src/test/java/org/neo4j/gds/modularityoptimization/FootballTest.java
index dfb8f26d47c..458b1b3bd09 100644
--- a/algo/src/test/java/org/neo4j/gds/modularityoptimization/FootballTest.java
+++ b/algo/src/test/java/org/neo4j/gds/modularityoptimization/FootballTest.java
@@ -28,7 +28,7 @@
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.properties.nodes.NodePropertyValues;
import org.neo4j.gds.compat.Neo4jProxy;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.HugeDoubleArray;
import org.neo4j.gds.core.utils.paged.HugeLongArray;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
@@ -127,7 +127,7 @@ private ModularityOptimizationResult compute(
properties,
concurrency,
minBatchSize,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
).compute();
}
diff --git a/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationTest.java b/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationTest.java
index 482a520b223..96f2f5c0043 100644
--- a/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationTest.java
+++ b/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationTest.java
@@ -35,7 +35,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryTree;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.extension.GdlExtension;
@@ -243,7 +243,7 @@ private ModularityOptimizationResult compute(
properties,
concurrency,
minBatchSize,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
).compute();
}
diff --git a/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationWithoutOrientationTest.java b/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationWithoutOrientationTest.java
index 312d3ce0d26..db0ef84da0f 100644
--- a/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationWithoutOrientationTest.java
+++ b/algo/src/test/java/org/neo4j/gds/modularityoptimization/ModularityOptimizationWithoutOrientationTest.java
@@ -34,7 +34,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryTree;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.extension.GdlExtension;
@@ -252,7 +252,7 @@ private ModularityOptimizationResult compute(
properties,
concurrency,
minBatchSize,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
).compute();
}
diff --git a/algo/src/test/java/org/neo4j/gds/msbfs/MultiSourceBFSAccessMethodsTest.java b/algo/src/test/java/org/neo4j/gds/msbfs/MultiSourceBFSAccessMethodsTest.java
index 88a176bbf84..f0b4fd9a4a6 100644
--- a/algo/src/test/java/org/neo4j/gds/msbfs/MultiSourceBFSAccessMethodsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/msbfs/MultiSourceBFSAccessMethodsTest.java
@@ -31,7 +31,7 @@
import org.neo4j.gds.api.RelationshipIterator;
import org.neo4j.gds.api.RelationshipWithPropertyConsumer;
import org.neo4j.gds.config.ConcurrencyConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.graphbuilder.DefaultBuilder;
import org.neo4j.gds.graphbuilder.GraphBuilder;
@@ -85,7 +85,7 @@ void testWithPredecessor() {
new long[]{0, 1}
);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
verify(bfsConsumerMock).accept(1, 0, toList(1));
verify(bfsConsumerMock).accept(2, 0, toList(2));
@@ -126,7 +126,7 @@ void testWithANP() {
new long[]{0, 1}
);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
verify(mock).accept(3, 1, toList(1, 2));
verify(mock).accept(4, 1, toList(1, 2));
@@ -148,7 +148,7 @@ void testPredecessorWithAllSources() {
(i, p, d, s) -> mock.accept(i + 1, p + 1, d, toList(s, x -> x + 1))
);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
verify(mock).accept(1, 3, 1, toList(3));
verify(mock).accept(1, 4, 1, toList(4));
@@ -199,7 +199,7 @@ void testANPWithAllSources() {
(i, d, s) -> mock.accept(i + 1, d, toList(s, x -> x + 1))
);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
verify(mock).accept(1, 1, toList(3, 4));
verify(mock).accept(2, 1, toList(3, 4));
@@ -270,7 +270,7 @@ void testParallel() {
}
}
);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
});
for (int i = 0; i < maxNodes; i++) {
@@ -382,7 +382,7 @@ public Stream streamRelationships(long nodeId, double fallba
}
},
sources);
- msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, Pools.DEFAULT);
+ msbfs.run(ConcurrencyConfig.DEFAULT_CONCURRENCY, DefaultPool.INSTANCE);
for (int i = 0; i < seen.length; i++) {
final int[] nodeSeen = seen[i];
diff --git a/algo/src/test/java/org/neo4j/gds/pagerank/PageRankConfigTest.java b/algo/src/test/java/org/neo4j/gds/pagerank/PageRankConfigTest.java
new file mode 100644
index 00000000000..4aa6ff1aa7c
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/pagerank/PageRankConfigTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.pagerank;
+
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.gds.extension.GdlExtension;
+import org.neo4j.gds.extension.GdlGraph;
+import org.neo4j.gds.extension.Inject;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@GdlExtension
+public class PageRankConfigTest {
+
+ @GdlGraph
+ private static final String DB_CYPHER =
+ "CREATE " +
+ " (a:node)," +
+ " (b:node)," +
+ "(a)-[:R]->(b)";
+
+
+ @Inject
+ GraphStore graphStore;
+
+ @Test
+ void shouldNotAllowNegativeSourceNodes() {
+
+ var config = PageRankStreamConfigImpl.builder()
+ .sourceNodes(List.of(-1337)).build();
+
+ assertThatThrownBy(() -> config.graphStoreValidation(
+ graphStore,
+ config.nodeLabelIdentifiers(graphStore),
+ config.internalRelationshipTypes(graphStore)
+ ))
+ .hasMessageContaining("Negative node ids are not supported for the field `sourceNodes`");
+
+ }
+
+ @Test
+ void shouldNotAllowNonExistantSourceNodes() {
+
+ var config = PageRankStreamConfigImpl.builder()
+ .sourceNodes(List.of(421337)).build();
+
+ assertThatThrownBy(() -> config.graphStoreValidation(
+ graphStore,
+ config.nodeLabelIdentifiers(graphStore),
+ config.internalRelationshipTypes(graphStore)
+ ))
+ .hasMessageContaining("sourceNodes nodes do not exist in the in-memory graph: ['421337']");
+
+ }
+}
diff --git a/algo/src/test/java/org/neo4j/gds/pagerank/PageRankTest.java b/algo/src/test/java/org/neo4j/gds/pagerank/PageRankTest.java
index 5db2c5025b7..e7b63ab09d0 100644
--- a/algo/src/test/java/org/neo4j/gds/pagerank/PageRankTest.java
+++ b/algo/src/test/java/org/neo4j/gds/pagerank/PageRankTest.java
@@ -169,15 +169,19 @@ void withSourceNodes(String sourceNodesString, String expectedPropertyKey) {
}
}
- @Test
- void shouldLogProgress() {
+ @ParameterizedTest
+ @EnumSource(Mode.class)
+ void shouldLogProgress(Mode mode) {
var maxIterations = 10;
var config = ImmutablePageRankConfig.builder()
.maxIterations(maxIterations)
.build();
- var progressTask = PageRankAlgorithmFactory.pagerankProgressTask(graph, config);
+ var factory = new PageRankAlgorithmFactory<>(mode);
+
+ var progressTask = factory.progressTask(graph, config);
var log = Neo4jProxy.testLog();
+
var progressTracker = new TestProgressTracker(
progressTask,
log,
@@ -185,7 +189,12 @@ void shouldLogProgress() {
EmptyTaskRegistryFactory.INSTANCE
);
- runOnPregel(graph, config, Mode.PAGE_RANK, progressTracker);
+ factory.build(
+ graph,
+ config,
+ progressTracker
+ )
+ .compute();
var progresses = progressTracker.getProgresses().stream()
.filter(it -> it.get() > 0)
@@ -207,22 +216,26 @@ void shouldLogProgress() {
.extracting(removingThreadId())
.contains(
formatWithLocale(
- "PageRank :: Compute iteration %d of %d :: Start",
+ "%s :: Compute iteration %d of %d :: Start",
+ mode.taskName(),
iteration,
config.maxIterations()
),
formatWithLocale(
- "PageRank :: Compute iteration %d of %d :: Finished",
+ "%s :: Compute iteration %d of %d :: Finished",
+ mode.taskName(),
iteration,
config.maxIterations()
),
formatWithLocale(
- "PageRank :: Master compute iteration %d of %d :: Start",
+ "%s :: Master compute iteration %d of %d :: Start",
+ mode.taskName(),
iteration,
config.maxIterations()
),
formatWithLocale(
- "PageRank :: Master compute iteration %d of %d :: Finished",
+ "%s :: Master compute iteration %d of %d :: Finished",
+ mode.taskName(),
iteration,
config.maxIterations()
)
@@ -231,8 +244,8 @@ void shouldLogProgress() {
assertThat(messages)
.extracting(removingThreadId())
.contains(
- "PageRank :: Start",
- "PageRank :: Finished"
+ formatWithLocale("%s :: Start", mode.taskName()),
+ formatWithLocale("%s :: Finished", mode.taskName())
);
}
@@ -681,16 +694,13 @@ PageRankResult runOnPregel(Graph graph, PageRankConfig config) {
}
PageRankResult runOnPregel(Graph graph, PageRankConfig config, Mode mode) {
- return runOnPregel(graph, config, mode, ProgressTracker.NULL_TRACKER);
- }
-
- PageRankResult runOnPregel(Graph graph, PageRankConfig config, Mode mode, ProgressTracker progressTracker) {
return new PageRankAlgorithmFactory<>(mode)
.build(
graph,
config,
- progressTracker
+ ProgressTracker.NULL_TRACKER
)
.compute();
}
+
}
diff --git a/algo/src/test/java/org/neo4j/gds/paths/ShortestPathConfigTest.java b/algo/src/test/java/org/neo4j/gds/paths/ShortestPathConfigTest.java
index 2354bcef27f..7700e926052 100644
--- a/algo/src/test/java/org/neo4j/gds/paths/ShortestPathConfigTest.java
+++ b/algo/src/test/java/org/neo4j/gds/paths/ShortestPathConfigTest.java
@@ -22,6 +22,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.core.CypherMapWrapper;
import org.neo4j.gds.paths.dijkstra.config.ShortestPathDijkstraStreamConfigImpl;
+import org.neo4j.gds.paths.yens.config.ShortestPathYensStreamConfigImpl;
import org.neo4j.kernel.impl.core.NodeEntity;
import static org.assertj.core.api.Assertions.assertThat;
@@ -55,6 +56,33 @@ void shouldAllowNodeIds() {
assertThat(config.targetNode()).isEqualTo(1337L);
}
+ @Test
+ void shouldNotAllowNegativeSourceNode() {
+
+ var config = ShortestPathYensStreamConfigImpl.builder()
+ .k(1)
+ .sourceNode(-1337)
+ .targetNode(0);
+
+ assertThatThrownBy(() -> config.build())
+ .hasMessageContaining("Negative node ids are not supported for the field `sourceNode`");
+
+ }
+
+ @Test
+ void shouldNotAllowNegativeTargetNode() {
+
+ var config = ShortestPathYensStreamConfigImpl.builder()
+ .k(1)
+ .sourceNode(0)
+ .targetNode(-1337);
+
+ assertThatThrownBy(() -> config.build())
+ .hasMessageContaining("Negative node ids are not supported for the field `targetNode`");
+
+ }
+
+
@Test
void shouldThrowErrorOnUnsupportedType() {
var cypherMapWrapper = CypherMapWrapper
diff --git a/algo/src/test/java/org/neo4j/gds/paths/delta/DeltaSteppingTest.java b/algo/src/test/java/org/neo4j/gds/paths/delta/DeltaSteppingTest.java
index e20bd89e0d1..bf6470e3644 100644
--- a/algo/src/test/java/org/neo4j/gds/paths/delta/DeltaSteppingTest.java
+++ b/algo/src/test/java/org/neo4j/gds/paths/delta/DeltaSteppingTest.java
@@ -36,7 +36,7 @@
import org.neo4j.gds.beta.generator.RelationshipDistribution;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.GraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -142,7 +142,7 @@ void singleSource(double delta, int concurrency, long idOffset) {
.build();
var paths = DeltaStepping
- .of(graph, config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER)
+ .of(graph, config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER)
.compute()
.pathSet();
@@ -172,7 +172,7 @@ void singleSourceFromDisconnectedNode(double delta, int concurrency, long idOffs
.build();
var paths = DeltaStepping
- .of(graph, config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER)
+ .of(graph, config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER)
.compute()
.pathSet();
@@ -191,7 +191,7 @@ void shouldLogProgress() {
var testLog = Neo4jProxy.testLog();
var progressTracker = new TestProgressTracker(progressTask, testLog, 1, EmptyTaskRegistryFactory.INSTANCE);
- DeltaStepping.of(graph, config, Pools.DEFAULT, progressTracker)
+ DeltaStepping.of(graph, config, DefaultPool.INSTANCE, progressTracker)
.compute()
.pathSet();
@@ -279,7 +279,7 @@ void singleSource(double delta, int concurrency, long idOffset) {
.build();
var paths = DeltaStepping
- .of(graph, config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER)
+ .of(graph, config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER)
.compute()
.pathSet();
@@ -335,7 +335,7 @@ void singleSource(double delta, int concurrency, long idOffset) {
.build();
var paths = DeltaStepping
- .of(graph, config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER)
+ .of(graph, config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER)
.compute()
.pathSet();
@@ -369,7 +369,7 @@ void shouldGiveSameResultsAsDijkstra() {
var deltaStepping = DeltaStepping.of(
newGraph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
diff --git a/algo/src/test/java/org/neo4j/gds/paths/traverse/BfsConfigTest.java b/algo/src/test/java/org/neo4j/gds/paths/traverse/BfsConfigTest.java
new file mode 100644
index 00000000000..5dfa1103552
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/paths/traverse/BfsConfigTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.paths.traverse;
+
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.gds.extension.GdlExtension;
+import org.neo4j.gds.extension.GdlGraph;
+import org.neo4j.gds.extension.IdFunction;
+import org.neo4j.gds.extension.Inject;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+@GdlExtension
+public class BfsConfigTest {
+
+ @GdlGraph
+ private static final String DB_CYPHER =
+ "CREATE " +
+ " (a:node)," +
+ " (b:node)," +
+ "(a)-[:R]->(b)";
+
+
+ @Inject
+ GraphStore graphStore;
+
+ @Inject
+ IdFunction idFunction;
+
+ @Test
+ void shouldNotAllowNegativeTargetNodes() {
+ var config = BfsStreamConfigImpl.builder()
+ .sourceNode(0L)
+ .targetNodes(List.of(idFunction.of("a"), -1337)).build();
+
+ assertThatThrownBy(() -> config.graphStoreValidation(
+ graphStore,
+ config.nodeLabelIdentifiers(graphStore),
+ config.internalRelationshipTypes(graphStore)
+ ))
+ .hasMessageContaining("Negative node ids are not supported for the field `targetNodes`");
+
+ }
+
+ @Test
+ void failOnInvalidEndNodes() {
+
+ var config = BfsStreamConfigImpl.builder()
+ .sourceNode(idFunction.of("a"))
+ .targetNodes(List.of(idFunction.of("b"), 421337)).build();
+
+ assertThatThrownBy(() -> config.graphStoreValidation(
+ graphStore,
+ config.nodeLabelIdentifiers(graphStore),
+ config.internalRelationshipTypes(graphStore)
+ ))
+ .hasMessageContaining("targetNodes nodes do not exist in the in-memory graph: ['421337']");
+ }
+}
diff --git a/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesMissingPropsTest.java b/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesMissingPropsTest.java
index 0ff42febad6..222f31e5be6 100644
--- a/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesMissingPropsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesMissingPropsTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.core.CypherMapWrapper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -55,7 +55,7 @@ void partialArrays() {
.nodeProperties(List.of("arrayOn4", "arrayOn1"))
.scaler(Max.buildFrom(CypherMapWrapper.empty()))
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var result = algo.compute();
var resultProperties = result.scaledProperties().toArray();
@@ -73,7 +73,7 @@ void testMissingScalar() {
.nodeProperties(List.of("a", "b", "c"))
.scaler(StdScore.buildFrom(CypherMapWrapper.empty()))
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var result = algo.compute();
var resultProperties = result.scaledProperties().toArray();
diff --git a/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesTest.java b/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesTest.java
index 057477e127b..026fa49575f 100644
--- a/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesTest.java
+++ b/algo/src/test/java/org/neo4j/gds/scaleproperties/ScalePropertiesTest.java
@@ -31,7 +31,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.CypherMapWrapper;
import org.neo4j.gds.core.GraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -79,7 +79,7 @@ void scaleSingleProperty() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.concurrency(1)
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var result = algo.compute();
var resultProperties = result.scaledProperties().toArray();
@@ -98,7 +98,7 @@ void scaleMultipleProperties() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.concurrency(1)
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var result = algo.compute();
var resultProperties = result.scaledProperties().toArray();
@@ -130,14 +130,14 @@ void parallelScale() {
bigGraph,
config.concurrency(4).build(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute().scaledProperties();
var expected = new ScaleProperties(
bigGraph,
config.concurrency(1).build(),
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute().scaledProperties();
IntStream.range(0, nodeCount).forEach(id -> assertEquals(expected.get(id)[0], parallelResult.get(id)[0]));
@@ -150,7 +150,7 @@ void scaleArrayProperty() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.build();
- var actual = new ScaleProperties(graph, arrayConfig, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var actual = new ScaleProperties(graph, arrayConfig, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
@@ -159,7 +159,7 @@ void scaleArrayProperty() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.build();
- var expected = new ScaleProperties(graph, singlePropConfig, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var expected = new ScaleProperties(graph, singlePropConfig, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
@@ -175,13 +175,13 @@ void supportLongAndFloatArrays(String scaler) {
var longArrayBConfig = baseConfigBuilder.nodeProperties(List.of("longArrayB")).build();
var doubleArrayBConfig = baseConfigBuilder.nodeProperties(List.of("floatArrayB")).build();
- var expected = new ScaleProperties(graph, bConfig, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var expected = new ScaleProperties(graph, bConfig, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
- var actualLong = new ScaleProperties(graph, longArrayBConfig, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var actualLong = new ScaleProperties(graph, longArrayBConfig, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
- var actualDouble = new ScaleProperties(graph, doubleArrayBConfig, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var actualDouble = new ScaleProperties(graph, doubleArrayBConfig, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
@@ -197,7 +197,7 @@ void supportDoubleArrays() {
var config = baseConfigBuilder.nodeProperties(List.of("doubleArray")).build();
var expected = new double[][]{new double[]{0.0}, new double[]{0.2499999722444236}, new double[]{.5}, new double[]{0.7500000277555764}, new double[]{1.0}};
- var actual = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT)
+ var actual = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE)
.compute()
.scaledProperties();
@@ -211,7 +211,7 @@ void failOnArrayPropertyWithUnequalLength() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var error = assertThrows(IllegalArgumentException.class, algo::compute);
assertThat(error.getMessage(), containsString(
@@ -226,7 +226,7 @@ void failOnNonExistentProperty() {
.scaler(MinMax.buildFrom(CypherMapWrapper.empty()))
.build();
- var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, Pools.DEFAULT);
+ var algo = new ScaleProperties(graph, config, ProgressTracker.NULL_TRACKER, DefaultPool.INSTANCE);
var error = assertThrows(IllegalArgumentException.class, algo::compute);
assertThat(error.getMessage(), containsString("Node property `IMAGINARY_PROP` not found in graph"));
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/knn/metrics/EuclideanTest.java b/algo/src/test/java/org/neo4j/gds/similarity/knn/metrics/EuclideanTest.java
new file mode 100644
index 00000000000..6769db1727b
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/similarity/knn/metrics/EuclideanTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.similarity.knn.metrics;
+
+import org.assertj.core.data.Offset;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class EuclideanTest {
+
+ @Test
+ void doubleArrays() {
+ var left = new double[] {0.008706967509313894d, 0.0d, 0.004919643078839634d, 0.007029592654453866d, 0.0d, 0.0d, 0.1257682851778286d, 0.016530303738513153d, 0.012745441170181648d, 0.0d};
+ var right = new double[] {0.008706967509313894d, 0.0d, 0.0041533258820686736d, 0.003698167604532474d, 0.0d, 0.0d, 0.14438303839785882d, 0.0017742178454893931d, 0.008013536500447603d, 0.0d};
+
+ var metric = Euclidean.doubleMetric(left, right);
+
+ assertThat(metric).isCloseTo(0.976123304363789d, Offset.offset(1e-5));
+ }
+
+ @Test
+ void floatArrays() {
+ var left = new float[] {0.008706967509313894f, 0.0f, 0.004919643078839634f, 0.007029592654453866f, 0.0f, 0.0f, 0.1257682851778286f, 0.016530303738513153f, 0.012745441170181648f, 0.0f};
+ var right = new float[] {0.008706967509313894f, 0.0f, 0.0041533258820686736f, 0.003698167604532474f, 0.0f, 0.0f, 0.14438303839785882f, 0.0017742178454893931f, 0.008013536500447603f, 0.0f};
+
+ var metric = Euclidean.floatMetric(left, right);
+
+ assertThat(metric).isCloseTo(0.976123304363789d, Offset.offset(1e-5));
+ }
+}
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputerTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputerTest.java
new file mode 100644
index 00000000000..9da7449cd8f
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/CosineSimilarityComputerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.similarity.nodesim;
+
+import org.assertj.core.data.Offset;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+class CosineSimilarityComputerTest {
+
+ @Test
+ void shouldComputeUnweightedCosineSimilarity() {
+ var array1 = new long[]{0, 1, 2, 4, 6};
+ var array2 = new long[]{0, 1, 2, 3, 5, 6, 7};
+ var similarityComputer = new CosineSimilarityComputer(0);
+
+ var cosineSimilarity = similarityComputer.computeSimilarity(array1, array2);
+
+ assertThat(cosineSimilarity).isCloseTo(0.6761234037828131, Offset.offset(1e-5));
+ }
+
+ @Test
+ void shouldComputeUnweightedCosineSimilarityRespectingCutoff() {
+ var array1 = new long[]{0, 1, 2, 4, 6};
+ var array2 = new long[]{0, 1, 2, 3, 5, 6, 7};
+ var similarityComputer = new CosineSimilarityComputer(0.7);
+
+ var cosineSimilarity = similarityComputer.computeSimilarity(array1, array2);
+
+ assertThat(cosineSimilarity).isNaN();
+ }
+
+ @Test
+ void shouldComputeCosineOnArraysWithNoMissingElements() {
+ var similarityComputer = new CosineSimilarityComputer(0);
+ var array1 = new long[]{0, 1, 2};
+ var weight1 = new double[]{0.5, 0.2, 0.6};
+ var array2 = new long[]{0, 1, 2};
+ var weight2 = new double[]{1.3, 0.9, 0.2};
+
+ assertThat(similarityComputer.computeWeightedSimilarity(array1, array2, weight1, weight2)).isCloseTo(
+ 0.73935,
+ Offset.offset(1e-5)
+ );
+ }
+
+ @Test
+ void shouldComputeCosineOnArraysWithNoMissingElementsRespectingCutoff() {
+ var similarityComputer = new CosineSimilarityComputer(1);
+ var array1 = new long[]{0, 1, 2};
+ var weight1 = new double[]{0.5, 0.2, 0.6};
+ var array2 = new long[]{0, 1, 2};
+ var weight2 = new double[]{1.3, 0.9, 0.2};
+
+ assertThat(similarityComputer.computeWeightedSimilarity(array1, array2, weight1, weight2)).isNaN();
+ }
+
+ @Test
+ void shouldComputeCosineOnArraysWithMissingElements() {
+ var similarityComputer = new CosineSimilarityComputer(0);
+ var array1 = new long[]{0, 1, 2, 4, 6};
+ var weight1 = new double[]{0.5, 0.2, 0.6, 0.8, 1};
+ var array2 = new long[]{0, 1, 2, 3, 5, 6, 7};
+ var weight2 = new double[]{1.3, 0.9, 0.2, 4.2, 1, 2, 3};
+
+ assertThat(similarityComputer.computeWeightedSimilarity(array1, array2, weight1, weight2)).isCloseTo(
+ 0.33344,
+ Offset.offset(1e-5)
+ );
+ }
+
+}
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputerTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputerTest.java
index f36a1ba506b..f944ddc92a5 100644
--- a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputerTest.java
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/MetricSimilarityComputerTest.java
@@ -21,6 +21,7 @@
import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class MetricSimilarityComputerTest {
@@ -31,4 +32,11 @@ void shouldThrowOnWrongMetric2() {
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("ovErLaPPPPP is not a valid metric");
}
+
+ @Test
+ void shouldParseCosineSimilarityComputer() {
+ var cosineComputer = MetricSimilarityComputer.parse("CosiNe").build(0);
+ assertThat(cosineComputer)
+ .isExactlyInstanceOf(CosineSimilarityComputer.class);
+ }
}
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTerminationTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTerminationTest.java
index d3ae7902e0c..599fc2d1348 100644
--- a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTerminationTest.java
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTerminationTest.java
@@ -23,7 +23,7 @@
import org.neo4j.gds.BaseTest;
import org.neo4j.gds.beta.generator.RandomGraphGenerator;
import org.neo4j.gds.beta.generator.RelationshipDistribution;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import static org.neo4j.gds.graphbuilder.TransactionTerminationTestUtils.assertTerminates;
@@ -44,7 +44,7 @@ void shouldTerminate() {
var nodeSimilarity = NodeSimilarity.create(
graph,
NodeSimilarityTest.configBuilder().concurrency(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
nodeSimilarity.setTerminationFlag(terminationFlag);
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTest.java
index 17d10622ca4..4e8a2448643 100644
--- a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/NodeSimilarityTest.java
@@ -32,7 +32,7 @@
import org.neo4j.gds.compat.TestLog;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.mem.MemoryEstimations;
import org.neo4j.gds.core.utils.mem.MemoryRange;
import org.neo4j.gds.core.utils.mem.MemoryTree;
@@ -291,7 +291,7 @@ void shouldComputeWeightedForSupportedDirections(Orientation orientation, int co
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().relationshipWeightProperty("prop").concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -311,7 +311,7 @@ void shouldComputeForSupportedDirections(Orientation orientation, int concurrenc
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -331,7 +331,7 @@ void shouldComputeTopNForSupportedDirections(Orientation orientation, int concur
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).topN(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -351,7 +351,7 @@ void shouldComputeNegativeTopNForSupportedDirections(Orientation orientation, in
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).bottomN(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -373,7 +373,7 @@ void shouldComputeTopKForSupportedDirections(Orientation orientation, int concur
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().topK(1).concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -397,7 +397,7 @@ void shouldComputeNegativeTopKForSupportedDirections(Orientation orientation, in
.topK(10)
.bottomK(1)
.build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -427,7 +427,7 @@ void shouldComputeWithSimilarityCutoffForSupportedDirections(Orientation orienta
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).similarityCutoff(0.1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -450,7 +450,7 @@ void shouldComputeWithDegreeCutoffForSupportedDirections(Orientation orientation
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().degreeCutoff(2).concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -471,7 +471,7 @@ void shouldComputeForUndirectedGraphs(int concurrency) {
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
undirectedGraph,
configBuilder().concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
Set result = nodeSimilarity.computeToStream().collect(Collectors.toSet());
@@ -483,7 +483,7 @@ void shouldComputeForUnionGraphs() {
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
naturalGraph,
configBuilder().concurrency(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
var result1 = nodeSimilarity.computeToStream().collect(Collectors.toSet());
@@ -491,7 +491,7 @@ void shouldComputeForUnionGraphs() {
nodeSimilarity = NodeSimilarity.create(
naturalUnionGraph,
configBuilder().concurrency(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
var result2 = nodeSimilarity.computeToStream().collect(Collectors.toSet());
@@ -507,7 +507,7 @@ void shouldComputeSimilarityGraphInAllSupportedDirections(Orientation orientatio
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -558,7 +558,7 @@ void shouldComputeToGraphWithUnusedNodesInInputGraph(Orientation orientation, in
.topK(100)
.topN(1)
.build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -596,7 +596,7 @@ void shouldIgnoreLoops(Orientation orientation, int concurrency) {
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).topN(1).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -623,7 +623,7 @@ void shouldIgnoreParallelEdges(Orientation orientation, int concurrency) {
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(concurrency).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -840,7 +840,7 @@ void shouldLogProgress(int concurrency) {
NodeSimilarity.create(
graph,
config,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
progressTracker
).compute().streamResult().count();
@@ -880,7 +880,7 @@ void shouldGiveCorrectResultsWithOverlap() {
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
graph,
configBuilder().concurrency(1).similarityMetric(MetricSimilarityComputer.parse("ovErLaP")).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -898,7 +898,7 @@ void shouldGiveCorrectResultsWithOverlap() {
.concurrency(1)
.similarityMetric(MetricSimilarityComputer.parse("ovErLaP"))
.build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -934,7 +934,7 @@ void shouldWorkForAllDegreeBoundsCombinations(int lowBound, int upperBound, Stri
NodeSimilarity nodeSimilarity = NodeSimilarity.create(
naturalGraph,
configBuilder().upperDegreeCutoff(upperBound).degreeCutoff(lowBound).build(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/SimilarityGraphBuilderTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/SimilarityGraphBuilderTest.java
index d71a5bb42ba..858524a05f0 100644
--- a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/SimilarityGraphBuilderTest.java
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/SimilarityGraphBuilderTest.java
@@ -22,7 +22,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.NodeLabel;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.huge.HugeGraph;
import org.neo4j.gds.core.huge.UnionGraph;
import org.neo4j.gds.core.loading.construction.GraphFactory;
@@ -73,7 +73,7 @@ void testConstructionFromHugeGraph() {
SimilarityGraphBuilder similarityGraphBuilder = new SimilarityGraphBuilder(
unlabelledGraph,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
TerminationFlag.RUNNING_TRUE
);
@@ -96,7 +96,7 @@ void testConstructionFromUnionGraph() {
SimilarityGraphBuilder similarityGraphBuilder = new SimilarityGraphBuilder(
graph,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
TerminationFlag.RUNNING_TRUE
);
@@ -131,7 +131,7 @@ void testConstructFromFilteredGraph() {
SimilarityGraphBuilder similarityGraphBuilder = new SimilarityGraphBuilder(
filteredIdMap,
1,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
TerminationFlag.RUNNING_TRUE
);
diff --git a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/UnionGraphWeightedNodeSimilarityTest.java b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/UnionGraphWeightedNodeSimilarityTest.java
index 0c4ab250cad..b7c371db0d7 100644
--- a/algo/src/test/java/org/neo4j/gds/similarity/nodesim/UnionGraphWeightedNodeSimilarityTest.java
+++ b/algo/src/test/java/org/neo4j/gds/similarity/nodesim/UnionGraphWeightedNodeSimilarityTest.java
@@ -22,7 +22,7 @@
import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Test;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -58,7 +58,7 @@ void shouldWorkWithUnionGraph(){
.topN(1)
.build();
- var nodeSimilarity = NodeSimilarity.create(graph, config, Pools.DEFAULT, ProgressTracker.NULL_TRACKER);
+ var nodeSimilarity = NodeSimilarity.create(graph, config, DefaultPool.INSTANCE, ProgressTracker.NULL_TRACKER);
var result = nodeSimilarity.compute().streamResult().findFirst().get();
//input should be (0 + 10 + 0)/ (5 + 10 + 8) = 10/23
diff --git a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathSteinerAlgorithmExtendedTest.java b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathSteinerAlgorithmExtendedTest.java
index 5d21acddb47..b826bccc72a 100644
--- a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathSteinerAlgorithmExtendedTest.java
+++ b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathSteinerAlgorithmExtendedTest.java
@@ -25,7 +25,7 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.Orientation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -155,7 +155,7 @@ void shouldWorkCorrectly(double delta, int binSizeThreshold) {
false,
binSizeThreshold,
//setting custom threshold for such a small graph allows to not examine everything in a single iteration
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
@@ -175,7 +175,7 @@ void shouldWorkCorrectlyWithLineGraph() {
2.0,
1,
false,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
)
.compute();
@@ -203,7 +203,7 @@ void deltaSteppingShouldWorkCorrectly() {
isTerminal,
1,
SteinerBasedDeltaStepping.BIN_SIZE_THRESHOLD,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
var result = deltaSteiner.compute().pathSet();
@@ -229,7 +229,7 @@ void shouldWorkIfRevisitsVertices() {
2.0,
1,
false,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
@@ -258,7 +258,7 @@ void shouldWorkOnTriangle() {
2.0,
1,
false,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
diff --git a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmReroutingTest.java b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmReroutingTest.java
index 4e97db509ab..688070202ad 100644
--- a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmReroutingTest.java
+++ b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmReroutingTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.TestProgressTracker;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.core.utils.progress.tasks.Task;
@@ -189,7 +189,7 @@ void shouldPruneUnusedIfRerouting() {
2.0,
1,
false,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResult.totalCost()).isEqualTo(7.0);
@@ -203,7 +203,7 @@ void shouldPruneUnusedIfRerouting() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(4.0);
@@ -223,7 +223,7 @@ void shouldPruneUnusedIfReroutingOnInvertedIndex() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(4.0);
@@ -242,7 +242,7 @@ void rerouteShouldNotCreateLoops() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
var parent = steinerResult.parentArray().toArray();
@@ -267,7 +267,7 @@ void rerouteShouldNotCreateLoopsOnInvertedIndex() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
var parent = steinerResult.parentArray().toArray();
@@ -294,7 +294,7 @@ void shouldWorkForUnreachableAndReachableTerminals() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerTreeResult.effectiveTargetNodesCount()).isEqualTo(2);
@@ -315,7 +315,7 @@ void shouldWorkIfNoReachableTerminals() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerTreeResult.effectiveTargetNodesCount()).isEqualTo(0);
@@ -473,7 +473,7 @@ void shouldNotGetOptimalWithoutBetterRerouting() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(25.0);
@@ -498,7 +498,7 @@ void shouldHandleMultiplePruningsOnSameTreeAndGetBetter() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(22.0);
@@ -522,7 +522,7 @@ void shouldNotPruneUnprunableNodes() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(170.0 - 19);
@@ -546,7 +546,7 @@ void shouldTakeAdvantageOfNewSingleParents() {
2.0,
1,
true,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
assertThat(steinerResultWithReroute.totalCost()).isEqualTo(20);
@@ -554,5 +554,3 @@ void shouldTakeAdvantageOfNewSingleParents() {
}
}
-
-
diff --git a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmTest.java b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmTest.java
index 9abd7b58c0c..d057bcb99e7 100644
--- a/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmTest.java
+++ b/algo/src/test/java/org/neo4j/gds/steiner/ShortestPathsSteinerAlgorithmTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.Orientation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -75,7 +75,7 @@ void shouldWorkCorrectly() {
2.0,
1,
false,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).compute();
var pruned = ShortestPathsSteinerAlgorithm.PRUNED;
diff --git a/algo/src/test/java/org/neo4j/gds/traversal/RandomWalkTest.java b/algo/src/test/java/org/neo4j/gds/traversal/RandomWalkTest.java
index f1dde921af3..689a1b8186a 100644
--- a/algo/src/test/java/org/neo4j/gds/traversal/RandomWalkTest.java
+++ b/algo/src/test/java/org/neo4j/gds/traversal/RandomWalkTest.java
@@ -34,7 +34,7 @@
import org.neo4j.gds.beta.generator.RelationshipDistribution;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.compat.TestLog;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.TerminationFlag;
import org.neo4j.gds.core.utils.progress.GlobalTaskStore;
import org.neo4j.gds.core.utils.progress.TaskRegistryFactory;
@@ -95,7 +95,7 @@ void testWithDefaultConfig() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
List result = randomWalk.compute().collect(Collectors.toList());
@@ -136,7 +136,7 @@ private List runRandomWalkSeeded(Node2VecStreamConfig config, Graph grap
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
return randomWalk.compute().collect(Collectors.toList());
@@ -149,7 +149,7 @@ void testSampleFromMultipleRelationshipTypes() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
int expectedNumberOfWalks = config.walksPerNode() * 3;
@@ -190,7 +190,7 @@ void returnFactorShouldMakeWalksIncludeStartNodeMoreOften() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var nodeCounter = new HashMap();
@@ -250,7 +250,7 @@ void largeInOutFactorShouldMakeTheWalkKeepTheSameDistance() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var nodeCounter = new HashMap();
@@ -299,7 +299,7 @@ void shouldRespectRelationshipWeights() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var nodeCounter = new HashMap();
@@ -336,7 +336,7 @@ void failOnInvalidRelationshipWeights(double invalidWeight) {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
)
).isInstanceOf(RuntimeException.class)
.hasMessage(
@@ -371,7 +371,7 @@ void parallelWeighted() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(randomWalk.compute().collect(Collectors.toList()))
@@ -400,7 +400,7 @@ void testWithConfiguredOffsetStartNodes() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
assertThat(randomWalk.compute().collect(Collectors.toList()))
@@ -423,7 +423,7 @@ void testSetTerminationFlagAndMultipleRuns() {
graph,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
);
var stream = randomWalk.compute();
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountFilteredGraphTest.java b/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountFilteredGraphTest.java
index 98501e94fbb..7a146f23688 100644
--- a/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountFilteredGraphTest.java
+++ b/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountFilteredGraphTest.java
@@ -29,7 +29,7 @@
import org.neo4j.gds.StoreLoaderBuilder;
import org.neo4j.gds.api.GraphStore;
import org.neo4j.gds.core.Aggregation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.extension.Neo4jGraph;
import java.util.Collections;
@@ -40,7 +40,7 @@
class IntersectingTriangleCountFilteredGraphTest extends BaseTest {
- @Neo4jGraph
+ @Neo4jGraph(offsetIds = true)
static final String DB_CYPHER = "CREATE " +
" (a1:A)" +
", (a2:A)" +
@@ -78,7 +78,7 @@ void testUnionGraphWithNodeFilter() {
Optional.empty()
);
var config = ImmutableTriangleCountBaseConfig.builder().build();
- var triangleCount = IntersectingTriangleCount.create(graph, config, Pools.DEFAULT);
+ var triangleCount = IntersectingTriangleCount.create(graph, config, DefaultPool.INSTANCE);
var triangleCountResult = triangleCount.compute();
assertThat(triangleCountResult.globalTriangles()).isEqualTo(1);
var triangles = triangleCountResult.localTriangles();
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountTest.java b/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountTest.java
index 5d189682de5..a3403f05824 100644
--- a/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountTest.java
+++ b/algo/src/test/java/org/neo4j/gds/triangle/IntersectingTriangleCountTest.java
@@ -27,7 +27,7 @@
import org.neo4j.gds.Orientation;
import org.neo4j.gds.TestSupport;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import java.util.stream.Stream;
@@ -531,7 +531,7 @@ private TriangleCountResult compute(Graph graph) {
}
private TriangleCountResult compute(Graph graph, TriangleCountBaseConfig config) {
- return IntersectingTriangleCount.create(graph, config, Pools.DEFAULT).compute();
+ return IntersectingTriangleCount.create(graph, config, DefaultPool.INSTANCE).compute();
}
private static Graph fromGdl(String gdl) {
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/LargeIntersectingTriangleCountTest.java b/algo/src/test/java/org/neo4j/gds/triangle/LargeIntersectingTriangleCountTest.java
index 3e7722bb1c3..23f5eea35f7 100644
--- a/algo/src/test/java/org/neo4j/gds/triangle/LargeIntersectingTriangleCountTest.java
+++ b/algo/src/test/java/org/neo4j/gds/triangle/LargeIntersectingTriangleCountTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.Orientation;
import org.neo4j.gds.StoreLoaderBuilder;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.PagedAtomicIntegerArray;
import org.neo4j.gds.graphbuilder.DefaultBuilder;
import org.neo4j.gds.graphbuilder.GraphBuilder;
@@ -71,7 +71,7 @@ void testQueue() {
var result = IntersectingTriangleCount.create(
graph,
defaultConfigBuilder().build(),
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
assertEquals(TRIANGLE_COUNT, result.globalTriangles());
assertTriangles(result.globalTriangles());
@@ -83,7 +83,7 @@ void testQueueParallel() {
var result = IntersectingTriangleCount.create(
graph,
defaultConfigBuilder().concurrency(4).build(),
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
assertEquals(TRIANGLE_COUNT, result.globalTriangles());
assertTriangles(result.globalTriangles());
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/TriangleCountMaxDegreeTest.java b/algo/src/test/java/org/neo4j/gds/triangle/TriangleCountMaxDegreeTest.java
new file mode 100644
index 00000000000..e311c8a9ab1
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/triangle/TriangleCountMaxDegreeTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.triangle;
+
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.api.schema.Direction;
+import org.neo4j.gds.beta.generator.RandomGraphGenerator;
+import org.neo4j.gds.beta.generator.RelationshipDistribution;
+import org.neo4j.gds.core.concurrency.DefaultPool;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class TriangleCountMaxDegreeTest {
+
+ @Test
+ void shouldWorkWithMaxDegree(){
+ var graph= RandomGraphGenerator.builder().nodeCount(24).averageDegree(23).seed(101)
+ .relationshipDistribution(
+ RelationshipDistribution.RANDOM)
+ .direction(Direction.UNDIRECTED)
+ .build().generate();
+
+ TriangleCountBaseConfig config = ImmutableTriangleCountBaseConfig
+ .builder()
+ .maxDegree(100)
+ .build();
+
+ var tc = IntersectingTriangleCount.create(graph, config, DefaultPool.INSTANCE).compute();
+ assertThat(tc.globalTriangles()).isEqualTo(1262L);
+
+ }
+
+}
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/TriangleStreamTest.java b/algo/src/test/java/org/neo4j/gds/triangle/TriangleStreamTest.java
index 665b2b15981..6a29c4ca063 100644
--- a/algo/src/test/java/org/neo4j/gds/triangle/TriangleStreamTest.java
+++ b/algo/src/test/java/org/neo4j/gds/triangle/TriangleStreamTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.Orientation;
import org.neo4j.gds.StoreLoaderBuilder;
import org.neo4j.gds.api.Graph;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.graphbuilder.DefaultBuilder;
import org.neo4j.gds.graphbuilder.GraphBuilder;
import org.neo4j.graphdb.Node;
@@ -73,7 +73,7 @@ void setupGraphDb() {
void testSequential() {
TripleConsumer mock = mock(TripleConsumer.class);
- TriangleStream.create(graph, Pools.DEFAULT, 1)
+ TriangleStream.create(graph, DefaultPool.INSTANCE, 1)
.compute()
.forEach(r -> mock.consume(r.nodeA, r.nodeB, r.nodeC));
@@ -84,7 +84,7 @@ void testSequential() {
void testParallel() {
TripleConsumer mock = mock(TripleConsumer.class);
- TriangleStream.create(graph, Pools.DEFAULT, 8)
+ TriangleStream.create(graph, DefaultPool.INSTANCE, 8)
.compute()
.forEach(r -> mock.consume(r.nodeA, r.nodeB, r.nodeC));
diff --git a/algo/src/test/java/org/neo4j/gds/triangle/UnionGraphTriangleCountingTest.java b/algo/src/test/java/org/neo4j/gds/triangle/UnionGraphTriangleCountingTest.java
new file mode 100644
index 00000000000..1e71af7ac17
--- /dev/null
+++ b/algo/src/test/java/org/neo4j/gds/triangle/UnionGraphTriangleCountingTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.triangle;
+
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.Orientation;
+import org.neo4j.gds.api.Graph;
+import org.neo4j.gds.core.concurrency.DefaultPool;
+import org.neo4j.gds.extension.GdlExtension;
+import org.neo4j.gds.extension.GdlGraph;
+import org.neo4j.gds.extension.Inject;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+@GdlExtension
+class UnionGraphTriangleCountingTest {
+ @GdlGraph(orientation = Orientation.UNDIRECTED)
+ static String DB_CYPHER="CREATE "+
+ "(a0:L4)," +
+ "(a1:L1)," +
+ "(a2:L3)," +
+ "(a3:L1)," +
+ "(a5:L3)," +
+ "(a6:L1)," +
+ "(a7:L4)," +
+ "(a8:L3)," +
+ "(a9:L4)," +
+ "(a10:L1)," +
+ "(a11:L1)," +
+ "(a12:L4)," +
+ "(a13:L4)," +
+ "(a14:L3)," +
+ "(a15:L3)," +
+ "(a17:L4)," +
+ "(a18:L0)," +
+ "(a19:L3)," +
+ "(a20:L1)," +
+ "(a21:L1)," +
+ "(a22:L1)," +
+ "(a23:L2)," +
+ "(a24:L4)," +
+ "(a25:L3)," +
+ "(a26:L0)," +
+ "(a28:L4)," +
+ "(a29:L4)," +
+ "(a11)-[:T1]->(a15), "+
+ "(a0)-[:T1]->(a21), "+
+ "(a8)-[:T2]->(a28), "+
+ "(a12)-[:T3]->(a12), "+
+ "(a9)-[:T4]->(a10), "+
+ "(a3)-[:T2]->(a26), "+
+ "(a7)-[:T0]->(a21), "+
+ "(a11)-[:T3]->(a29), "+
+ "(a1)-[:T3]->(a14), "+
+ "(a14)-[:T0]->(a22), "+
+ "(a10)-[:T1]->(a13), "+
+ "(a3)-[:T0]->(a21), "+
+ "(a5)-[:T3]->(a28), "+
+ "(a10)-[:T3]->(a25), "+
+ "(a8)-[:T1]->(a14), "+
+ "(a11)-[:T3]->(a15), "+
+ "(a13)-[:T2]->(a18), "+
+ "(a13)-[:T4]->(a20), "+
+ "(a6)-[:T1]->(a29), "+
+ "(a12)-[:T3]->(a14), "+
+ "(a3)-[:T2]->(a21), "+
+ "(a2)-[:T1]->(a21), "+
+ "(a0)-[:T0]->(a20), "+
+ "(a24)-[:T0]->(a29), "+
+ "(a10)-[:T4]->(a19), "+
+ "(a0)-[:T1]->(a28), "+
+ "(a9)-[:T4]->(a17), "+
+ "(a15)-[:T4]->(a21), "+
+ "(a21)-[:T1]->(a24) ";
+
+ @Inject
+ Graph graph;
+
+ @Test
+ void shouldWorkWithUnionGraphs() {
+ var config=TriangleCountStreamConfigImpl.builder().concurrency(1).build();
+ var a=IntersectingTriangleCount.create(graph,config, DefaultPool.INSTANCE);
+ var result=a.compute();
+ assertThat(result.globalTriangles()).isEqualTo(0);
+ }
+}
diff --git a/algo/src/test/java/org/neo4j/gds/undirected/ToUndirectedTest.java b/algo/src/test/java/org/neo4j/gds/undirected/ToUndirectedTest.java
index b09420ea94e..94ecc433dbc 100644
--- a/algo/src/test/java/org/neo4j/gds/undirected/ToUndirectedTest.java
+++ b/algo/src/test/java/org/neo4j/gds/undirected/ToUndirectedTest.java
@@ -28,7 +28,7 @@
import org.neo4j.gds.api.GraphStore;
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.Aggregation;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.SingleTypeRelationships;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -82,7 +82,7 @@ void shouldCreateUndirectedRelationships(int concurrency) {
directedGraphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
directedGraphStore.addRelationshipType(undirectedRelationships);
@@ -129,7 +129,7 @@ void shouldCreateUndirectedRelationshipsWithSingleRelationshipProperty(int concu
singleDirectedGraphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
singleDirectedGraphStore.addRelationshipType(undirectedRelationships);
@@ -175,7 +175,7 @@ void shouldCreateUndirectedRelationshipsWithNoRelationshipProperty(int concurren
noPropertyDirectedGraphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
noPropertyDirectedGraphStore.addRelationshipType(undirectedRelationships);
@@ -207,7 +207,7 @@ void shouldAggregateWithoutProperties() {
inputGraphStore,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
inputGraphStore.addRelationshipType(undirectedRels);
@@ -240,7 +240,7 @@ void shouldAggregateWithPropertiesAndGlobalAggregation() {
input,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
input.addRelationshipType(aggregatedUndirectedRelationships);
@@ -281,7 +281,7 @@ void shouldAggregateWithPropertiesAndLocalAggregation() {
input,
config,
ProgressTracker.NULL_TRACKER,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
input.addRelationshipType(aggregatedUndirectedRelationships);
diff --git a/algo/src/test/java/org/neo4j/gds/walking/CollapseMultiPathsTest.java b/algo/src/test/java/org/neo4j/gds/walking/CollapseMultiPathsTest.java
index d5d3dfc3647..08fb482dda8 100644
--- a/algo/src/test/java/org/neo4j/gds/walking/CollapseMultiPathsTest.java
+++ b/algo/src/test/java/org/neo4j/gds/walking/CollapseMultiPathsTest.java
@@ -26,7 +26,7 @@
import org.neo4j.gds.api.AdjacencyList;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.GraphStore;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
import org.neo4j.gds.extension.IdFunction;
@@ -112,7 +112,7 @@ void shouldFollowRoutesFromMovies() {
false,
RelationshipType.of("REL"),
2,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
@@ -174,7 +174,7 @@ void shouldTurnEveryRouteIntoRelationship() {
false,
RelationshipType.of("REL"),
2,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
diff --git a/algo/src/test/java/org/neo4j/gds/walking/CollapsePathTest.java b/algo/src/test/java/org/neo4j/gds/walking/CollapsePathTest.java
index 933e43901d7..02a83910f84 100644
--- a/algo/src/test/java/org/neo4j/gds/walking/CollapsePathTest.java
+++ b/algo/src/test/java/org/neo4j/gds/walking/CollapsePathTest.java
@@ -25,7 +25,7 @@
import org.neo4j.gds.RelationshipType;
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.GraphStore;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.loading.SingleTypeRelationships;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -123,7 +123,7 @@ void testCreatingRelationships() {
false,
RelationshipType.of("SAME_DRUG"),
2,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
@@ -139,7 +139,7 @@ void testAllowCreatingSelfLoops() {
true,
RelationshipType.of("SAME_DRUG"),
2,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
@@ -153,7 +153,7 @@ void runWithDifferentRelationshipTypes() {
false,
RelationshipType.of("SAME_DRUG"),
2,
- Pools.DEFAULT
+ DefaultPool.INSTANCE
).compute();
assertResultGraph(tookGraphStore, relationships, EXPECTED_WITHOUT_LOOPS);
diff --git a/algo/src/test/java/org/neo4j/gds/wcc/IncrementalWccTest.java b/algo/src/test/java/org/neo4j/gds/wcc/IncrementalWccTest.java
index 9ced3d34b69..65bd6e58e79 100644
--- a/algo/src/test/java/org/neo4j/gds/wcc/IncrementalWccTest.java
+++ b/algo/src/test/java/org/neo4j/gds/wcc/IncrementalWccTest.java
@@ -24,7 +24,7 @@
import org.neo4j.gds.api.Graph;
import org.neo4j.gds.api.IdMap;
import org.neo4j.gds.config.ConcurrencyConfig;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.dss.DisjointSetStruct;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -125,7 +125,7 @@ void shouldAssignMinimumCommunityIdOnMerge() {
private DisjointSetStruct run(Graph graph, WccBaseConfig config) {
return new Wcc(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
COMMUNITY_SIZE / ConcurrencyConfig.DEFAULT_CONCURRENCY,
config,
ProgressTracker.NULL_TRACKER
diff --git a/algo/src/test/java/org/neo4j/gds/wcc/WccTest.java b/algo/src/test/java/org/neo4j/gds/wcc/WccTest.java
index 88cbde8ba0e..9c2402ee096 100644
--- a/algo/src/test/java/org/neo4j/gds/wcc/WccTest.java
+++ b/algo/src/test/java/org/neo4j/gds/wcc/WccTest.java
@@ -35,7 +35,7 @@
import org.neo4j.gds.compat.Neo4jProxy;
import org.neo4j.gds.core.GraphDimensions;
import org.neo4j.gds.core.ImmutableGraphDimensions;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.dss.DisjointSetStruct;
import org.neo4j.gds.core.utils.progress.EmptyTaskRegistryFactory;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
@@ -280,7 +280,7 @@ DisjointSetStruct run(Graph graph, WccBaseConfig config) {
DisjointSetStruct run(Graph graph, WccBaseConfig config, int concurrency) {
return new Wcc(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
communitySize() / concurrency,
config,
ProgressTracker.NULL_TRACKER
diff --git a/algo/src/test/java/org/neo4j/gds/wcc/WccThresholdTest.java b/algo/src/test/java/org/neo4j/gds/wcc/WccThresholdTest.java
index 228b1ab852f..7b05ab90234 100644
--- a/algo/src/test/java/org/neo4j/gds/wcc/WccThresholdTest.java
+++ b/algo/src/test/java/org/neo4j/gds/wcc/WccThresholdTest.java
@@ -23,7 +23,7 @@
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.neo4j.gds.CommunityHelper;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.paged.dss.DisjointSetStruct;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
@@ -110,7 +110,7 @@ private void assertResults(double threshold, TestGraph graph, String[][] expecte
DisjointSetStruct dss = new Wcc(
graph,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
DEFAULT_BATCH_SIZE,
wccConfig,
ProgressTracker.NULL_TRACKER
diff --git a/alpha/alpha-proc/src/main/java/org/neo4j/gds/pregel/Hits.java b/alpha/alpha-proc/src/main/java/org/neo4j/gds/pregel/Hits.java
index 2dd1a02ea72..9f2e104898d 100644
--- a/alpha/alpha-proc/src/main/java/org/neo4j/gds/pregel/Hits.java
+++ b/alpha/alpha-proc/src/main/java/org/neo4j/gds/pregel/Hits.java
@@ -171,7 +171,9 @@ default String authProperty() {
return "auth";
}
- @Override
+ @Value.Default
+ @Configuration.ConvertWith(method = "org.neo4j.gds.beta.pregel.Partitioning#parse")
+ @Configuration.ToMapValue("org.neo4j.gds.beta.pregel.Partitioning#toString")
default Partitioning partitioning() {
return Partitioning.AUTO;
}
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsMutateProcTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsMutateProcTest.java
new file mode 100644
index 00000000000..043113fc3e5
--- /dev/null
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsMutateProcTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.hits;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.BaseProcTest;
+import org.neo4j.gds.catalog.GraphProjectProc;
+import org.neo4j.gds.extension.Neo4jGraph;
+import org.neo4j.gds.pregel.HitsMutateProc;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+class HitsMutateProcTest extends BaseProcTest {
+
+ @Neo4jGraph
+ public static final String DB_CYPHER =
+ "CREATE" +
+ " (a:Website {name: 'A'})," +
+ " (b:Website {name: 'B'})," +
+ " (c:Website {name: 'C'})," +
+ " (d:Website {name: 'D'})," +
+ " (e:Website {name: 'E'})," +
+ " (f:Website {name: 'F'})," +
+ " (g:Website {name: 'G'})," +
+ " (h:Website {name: 'H'})," +
+ " (i:Website {name: 'I'})," +
+
+ " (a)-[:LINK]->(b)," +
+ " (a)-[:LINK]->(c)," +
+ " (a)-[:LINK]->(d)," +
+ " (b)-[:LINK]->(c)," +
+ " (b)-[:LINK]->(d)," +
+ " (c)-[:LINK]->(d)," +
+
+ " (e)-[:LINK]->(b)," +
+ " (e)-[:LINK]->(d)," +
+ " (e)-[:LINK]->(f)," +
+ " (e)-[:LINK]->(h)," +
+
+ " (f)-[:LINK]->(g)," +
+ " (f)-[:LINK]->(i)," +
+ " (f)-[:LINK]->(h)," +
+ " (g)-[:LINK]->(h)," +
+ " (g)-[:LINK]->(i)," +
+ " (h)-[:LINK]->(i)";
+
+ @BeforeEach
+ void setupGraph() throws Exception {
+ registerProcedures(
+ HitsMutateProc.class,
+ GraphProjectProc.class
+ );
+
+ runQuery(
+ "CALL gds.graph.project(" +
+ " 'myGraph'," +
+ " 'Website'," +
+ " {LINK: {indexInverse: true}}" +
+ ");");
+ }
+
+ @Test
+ void shouldRunWithoutError() {
+ assertThatNoException()
+ .as("The `HITS` write procedure should run without raising an exception.")
+ .isThrownBy(() -> runQuery("CALL gds.alpha.hits.mutate('myGraph', { hitsIterations: 1, writeProperty:'hits' })"));
+ }
+}
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsWriteProcTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsWriteProcTest.java
new file mode 100644
index 00000000000..4e8e136fb02
--- /dev/null
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/hits/HitsWriteProcTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.hits;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.BaseProcTest;
+import org.neo4j.gds.catalog.GraphProjectProc;
+import org.neo4j.gds.extension.Neo4jGraph;
+import org.neo4j.gds.pregel.HitsWriteProc;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+class HitsWriteProcTest extends BaseProcTest {
+
+ @Neo4jGraph
+ public static final String DB_CYPHER =
+ "CREATE" +
+ " (a:Website {name: 'A'})," +
+ " (b:Website {name: 'B'})," +
+ " (c:Website {name: 'C'})," +
+ " (d:Website {name: 'D'})," +
+ " (e:Website {name: 'E'})," +
+ " (f:Website {name: 'F'})," +
+ " (g:Website {name: 'G'})," +
+ " (h:Website {name: 'H'})," +
+ " (i:Website {name: 'I'})," +
+
+ " (a)-[:LINK]->(b)," +
+ " (a)-[:LINK]->(c)," +
+ " (a)-[:LINK]->(d)," +
+ " (b)-[:LINK]->(c)," +
+ " (b)-[:LINK]->(d)," +
+ " (c)-[:LINK]->(d)," +
+
+ " (e)-[:LINK]->(b)," +
+ " (e)-[:LINK]->(d)," +
+ " (e)-[:LINK]->(f)," +
+ " (e)-[:LINK]->(h)," +
+
+ " (f)-[:LINK]->(g)," +
+ " (f)-[:LINK]->(i)," +
+ " (f)-[:LINK]->(h)," +
+ " (g)-[:LINK]->(h)," +
+ " (g)-[:LINK]->(i)," +
+ " (h)-[:LINK]->(i)";
+
+ @BeforeEach
+ void setupGraph() throws Exception {
+ registerProcedures(
+ HitsWriteProc.class,
+ GraphProjectProc.class
+ );
+
+ runQuery(
+ "CALL gds.graph.project(" +
+ " 'myGraph'," +
+ " 'Website'," +
+ " {LINK: {indexInverse: true}}" +
+ ");");
+ }
+
+ @Test
+ void shouldRunWithoutError() {
+ assertThatNoException()
+ .as("The `HITS` mutate procedure should run without raising an exception.")
+ .isThrownBy(() -> runQuery("CALL gds.alpha.hits.write('myGraph', { hitsIterations: 1, mutateProperty:'hits' })"));
+ }
+}
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/HitsTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/HitsTest.java
index 5dcd1057599..a68d12abb9d 100644
--- a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/HitsTest.java
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/HitsTest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.beta.pregel.Pregel;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -65,7 +65,7 @@ void testHits() {
graph,
config,
new Hits(),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAMutateProcTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAMutateProcTest.java
new file mode 100644
index 00000000000..bd0230b44e8
--- /dev/null
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAMutateProcTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.pregel;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.BaseProcTest;
+import org.neo4j.gds.beta.generator.GraphGenerateProc;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+class SpeakerListenerLPAMutateProcTest extends BaseProcTest {
+
+ @BeforeEach
+ void setup() throws Exception {
+ registerProcedures(
+ SpeakerListenerLPAMutateProc.class,
+ GraphGenerateProc.class
+ );
+ }
+
+ @Test
+ void shouldNotFailWhenRunningOnNonWritableGraph() {
+ runQuery("CALL gds.beta.graph.generate('randomGraph', 5, 2, {relationshipSeed:19}) YIELD name, nodes, relationships, relationshipDistribution");
+
+ assertThatNoException().isThrownBy(
+ () -> runQuery("CALL gds.alpha.sllpa.mutate('randomGraph', {mutateProperty: 'm', maxIterations: 4, minAssociationStrength: 0.1})")
+ );
+ }
+}
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAStreamProcTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAStreamProcTest.java
new file mode 100644
index 00000000000..b38e06f46b8
--- /dev/null
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAStreamProcTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.pregel;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.BaseProcTest;
+import org.neo4j.gds.beta.generator.GraphGenerateProc;
+
+import static org.assertj.core.api.Assertions.assertThatNoException;
+
+class SpeakerListenerLPAStreamProcTest extends BaseProcTest {
+
+ @BeforeEach
+ void setup() throws Exception {
+ registerProcedures(
+ SpeakerListenerLPAStreamProc.class,
+ GraphGenerateProc.class
+ );
+ }
+
+ @Test
+ void shouldNotFailWhenRunningOnNonWritableGraph() {
+ runQuery("CALL gds.beta.graph.generate('randomGraph', 5, 2, {relationshipSeed:19}) YIELD name, nodes, relationships, relationshipDistribution");
+
+ assertThatNoException().isThrownBy(
+ () -> runQuery("CALL gds.alpha.sllpa.stream('randomGraph', {maxIterations: 4, minAssociationStrength: 0.1})")
+ );
+ }
+}
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPATest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPATest.java
index 30b5e70d348..4752a25b2a6 100644
--- a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPATest.java
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPATest.java
@@ -21,7 +21,7 @@
import org.junit.jupiter.api.Test;
import org.neo4j.gds.beta.pregel.Pregel;
-import org.neo4j.gds.core.concurrency.Pools;
+import org.neo4j.gds.core.concurrency.DefaultPool;
import org.neo4j.gds.core.utils.progress.tasks.ProgressTracker;
import org.neo4j.gds.extension.GdlExtension;
import org.neo4j.gds.extension.GdlGraph;
@@ -75,7 +75,7 @@ void testWithoutPruning() {
graph,
config,
new SpeakerListenerLPA(42),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -122,7 +122,7 @@ void prunesAwayAfterManyIterations() {
graph,
config,
new SpeakerListenerLPA(42),
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
);
@@ -164,7 +164,7 @@ void closesThreadLocal() {
graph,
config,
computation,
- Pools.DEFAULT,
+ DefaultPool.INSTANCE,
ProgressTracker.NULL_TRACKER
).run();
diff --git a/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAWriteProcTest.java b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAWriteProcTest.java
new file mode 100644
index 00000000000..8ade6371ef4
--- /dev/null
+++ b/alpha/alpha-proc/src/test/java/org/neo4j/gds/pregel/SpeakerListenerLPAWriteProcTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.pregel;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.neo4j.gds.BaseProcTest;
+import org.neo4j.gds.beta.generator.GraphGenerateProc;
+import org.neo4j.graphdb.QueryExecutionException;
+
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+class SpeakerListenerLPAWriteProcTest extends BaseProcTest {
+
+ @BeforeEach
+ void setup() throws Exception {
+ registerProcedures(
+ SpeakerListenerLPAWriteProc.class,
+ GraphGenerateProc.class
+ );
+ }
+
+ @Test
+ void shouldFailWhenRunningOnNonWritableGraph() {
+ runQuery("CALL gds.beta.graph.generate('randomGraph', 5, 2, {relationshipSeed:19}) YIELD name, nodes, relationships, relationshipDistribution");
+
+ assertThatExceptionOfType(QueryExecutionException.class)
+ .isThrownBy(
+ () -> runQuery("CALL gds.alpha.sllpa.write('randomGraph', {writeProperty: 'm', maxIterations: 4, minAssociationStrength: 0.1})")
+ )
+ .withRootCauseInstanceOf(IllegalArgumentException.class)
+ .withMessageContaining("The provided graph does not support `write` execution mode.");
+ }
+}
diff --git a/build.gradle b/build.gradle
index 6d2713de31c..bc8e4fd1d09 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,6 +35,10 @@ ext {
project(':neo4j-kernel-adapter-5.6'),
project(':neo4j-kernel-adapter-5.7'),
project(':neo4j-kernel-adapter-5.8'),
+ project(':neo4j-kernel-adapter-5.9'),
+ project(':neo4j-kernel-adapter-5.10'),
+ project(':neo4j-kernel-adapter-5.11'),
+ project(':neo4j-kernel-adapter-5.12'),
],
'storage-engine-adapter': [
project(':storage-engine-adapter-4.4'),
@@ -46,6 +50,10 @@ ext {
project(':storage-engine-adapter-5.6'),
project(':storage-engine-adapter-5.7'),
project(':storage-engine-adapter-5.8'),
+ project(':storage-engine-adapter-5.9'),
+ project(':storage-engine-adapter-5.10'),
+ project(':storage-engine-adapter-5.11'),
+ project(':storage-engine-adapter-5.12'),
]
]
}
diff --git a/compatibility/4.4/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_44/Neo4jProxyImpl.java b/compatibility/4.4/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_44/Neo4jProxyImpl.java
index 946ecd4b7e6..2d967bcf3e8 100644
--- a/compatibility/4.4/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_44/Neo4jProxyImpl.java
+++ b/compatibility/4.4/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_44/Neo4jProxyImpl.java
@@ -41,6 +41,7 @@
import org.neo4j.gds.compat.GdsDatabaseLayout;
import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
import org.neo4j.gds.compat.GraphDatabaseApiProxy;
import org.neo4j.gds.compat.InputEntityIdVisitor;
import org.neo4j.gds.compat.Neo4jProxyApi;
@@ -84,6 +85,7 @@
import org.neo4j.internal.kernel.api.RelationshipScanCursor;
import org.neo4j.internal.kernel.api.Scan;
import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
import org.neo4j.internal.kernel.api.procs.FieldSignature;
import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
@@ -107,6 +109,8 @@
import org.neo4j.kernel.api.KernelTransactionHandle;
import org.neo4j.kernel.api.procedure.CallableProcedure;
import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
import org.neo4j.kernel.database.NormalizedDatabaseName;
import org.neo4j.kernel.impl.coreapi.InternalTransaction;
import org.neo4j.kernel.impl.index.schema.IndexImporterFactoryImpl;
@@ -137,8 +141,10 @@
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static org.neo4j.gds.compat.InternalReadOps.countByIdGenerator;
@@ -511,7 +517,8 @@ public ProcedureSignature procedureSignature(
boolean caseInsensitive,
boolean systemProcedure,
boolean internal,
- boolean allowExpiredCredentials
+ boolean allowExpiredCredentials,
+ boolean threadSafe
) {
return new ProcedureSignature(
name,
@@ -803,4 +810,47 @@ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
var databaseManager = GraphDatabaseApiProxy.resolveDependency(databaseService, FabricDatabaseManager.class);
return databaseManager.isFabricDatabase(GraphDatabaseApiProxy.databaseId(databaseService).name());
}
+
+ @Override
+ public T lookupComponentProvider(Context ctx, Class component, boolean safe) throws ProcedureException {
+ var globalProcedures = GraphDatabaseApiProxy.resolveDependency(ctx.dependencyResolver(), GlobalProcedures.class);
+ return globalProcedures.lookupComponentProvider(component, safe).apply(ctx);
+ }
+
+ @Override
+ public GlobalProcedureRegistry globalProcedureRegistry(GlobalProcedures globalProcedures) {
+ return new GlobalProcedureRegistry() {
+ @Override
+ public Set getAllProcedures() {
+ return globalProcedures.getAllProcedures();
+ }
+
+ @Override
+ public Stream getAllNonAggregatingFunctions() {
+ return globalProcedures.getAllNonAggregatingFunctions();
+ }
+
+ @Override
+ public Stream getAllAggregatingFunctions() {
+ return globalProcedures.getAllAggregatingFunctions();
+ }
+ };
+ }
+
+ private static final DependencyResolver EMPTY_DEPENDENCY_RESOLVER = new DependencyResolver.Adapter() {
+ @Override
+ public T resolveDependency(Class type, SelectionStrategy selector) {
+ return null;
+ }
+
+ @Override
+ public boolean containsDependency(Class> type) {
+ return false;
+ }
+ };
+
+ @Override
+ public DependencyResolver emptyDependencyResolver() {
+ return EMPTY_DEPENDENCY_RESOLVER;
+ }
}
diff --git a/compatibility/4.4/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_44/StorageEngineProxyImpl.java b/compatibility/4.4/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_44/StorageEngineProxyImpl.java
index e31769817d3..a82ceac1064 100644
--- a/compatibility/4.4/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_44/StorageEngineProxyImpl.java
+++ b/compatibility/4.4/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_44/StorageEngineProxyImpl.java
@@ -22,7 +22,6 @@
import org.neo4j.common.Edition;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
-import org.neo4j.counts.CountsAccessor;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
@@ -35,15 +34,12 @@
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
-import org.neo4j.internal.recordstorage.InMemoryStorageReader44;
import org.neo4j.io.layout.DatabaseLayout;
-import org.neo4j.storageengine.api.CommandCreationContext;
import org.neo4j.storageengine.api.PropertySelection;
import org.neo4j.storageengine.api.RelationshipSelection;
import org.neo4j.storageengine.api.StorageEngine;
import org.neo4j.storageengine.api.StorageEntityCursor;
import org.neo4j.storageengine.api.StoragePropertyCursor;
-import org.neo4j.storageengine.api.StorageReader;
import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
import org.neo4j.token.TokenHolders;
@@ -51,11 +47,6 @@
public class StorageEngineProxyImpl implements StorageEngineProxyApi {
- @Override
- public CommandCreationContext inMemoryCommandCreationContext() {
- return new InMemoryCommandCreationContextImpl();
- }
-
@Override
public void initRelationshipTraversalCursorForRelType(
StorageRelationshipTraversalCursor cursor,
@@ -69,13 +60,6 @@ public void initRelationshipTraversalCursorForRelType(
cursor.init(sourceNodeId, -1, relationshipSelection);
}
- @Override
- public StorageReader inMemoryStorageReader(
- CypherGraphStore graphStore, TokenHolders tokenHolders, CountsAccessor counts
- ) {
- return new InMemoryStorageReader44(graphStore, tokenHolders, counts);
- }
-
@Override
public StorageEngine createInMemoryStorageEngine(DatabaseLayout databaseLayout, TokenHolders tokenHolders) {
return new InMemoryStorageEngineImpl(databaseLayout, tokenHolders);
diff --git a/compatibility/5.1/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_51/Neo4jProxyImpl.java b/compatibility/5.1/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_51/Neo4jProxyImpl.java
index d42c6df7c5b..30a659e7815 100644
--- a/compatibility/5.1/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_51/Neo4jProxyImpl.java
+++ b/compatibility/5.1/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_51/Neo4jProxyImpl.java
@@ -44,6 +44,7 @@
import org.neo4j.gds.compat.GdsDatabaseLayout;
import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
import org.neo4j.gds.compat.GraphDatabaseApiProxy;
import org.neo4j.gds.compat.InputEntityIdVisitor;
import org.neo4j.gds.compat.Neo4jProxyApi;
@@ -87,6 +88,7 @@
import org.neo4j.internal.kernel.api.Scan;
import org.neo4j.internal.kernel.api.TokenPredicate;
import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
import org.neo4j.internal.kernel.api.procs.FieldSignature;
import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
@@ -113,6 +115,8 @@
import org.neo4j.kernel.api.KernelTransactionHandle;
import org.neo4j.kernel.api.procedure.CallableProcedure;
import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
import org.neo4j.kernel.database.NormalizedDatabaseName;
import org.neo4j.kernel.impl.coreapi.InternalTransaction;
import org.neo4j.kernel.impl.index.schema.IndexImporterFactoryImpl;
@@ -147,8 +151,10 @@
import java.util.List;
import java.util.Locale;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static java.lang.String.format;
import static org.neo4j.gds.compat.InternalReadOps.countByIdGenerator;
@@ -605,7 +611,8 @@ public ProcedureSignature procedureSignature(
boolean caseInsensitive,
boolean systemProcedure,
boolean internal,
- boolean allowExpiredCredentials
+ boolean allowExpiredCredentials,
+ boolean threadSafe
) {
return new ProcedureSignature(
name,
@@ -920,4 +927,47 @@ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
var databaseManager = GraphDatabaseApiProxy.resolveDependency(databaseService, FabricDatabaseManager.class);
return databaseManager.isFabricDatabase(GraphDatabaseApiProxy.databaseId(databaseService));
}
+
+ @Override
+ public T lookupComponentProvider(Context ctx, Class component, boolean safe) throws ProcedureException {
+ var globalProcedures = GraphDatabaseApiProxy.resolveDependency(ctx.dependencyResolver(), GlobalProcedures.class);
+ return globalProcedures.lookupComponentProvider(component, safe).apply(ctx);
+ }
+
+ @Override
+ public GlobalProcedureRegistry globalProcedureRegistry(GlobalProcedures globalProcedures) {
+ return new GlobalProcedureRegistry() {
+ @Override
+ public Set getAllProcedures() {
+ return globalProcedures.getAllProcedures();
+ }
+
+ @Override
+ public Stream getAllNonAggregatingFunctions() {
+ return globalProcedures.getAllNonAggregatingFunctions();
+ }
+
+ @Override
+ public Stream getAllAggregatingFunctions() {
+ return globalProcedures.getAllAggregatingFunctions();
+ }
+ };
+ }
+
+ private static final DependencyResolver EMPTY_DEPENDENCY_RESOLVER = new DependencyResolver.Adapter() {
+ @Override
+ public T resolveDependency(Class type, DependencyResolver.SelectionStrategy selector) {
+ return null;
+ }
+
+ @Override
+ public boolean containsDependency(Class> type) {
+ return false;
+ }
+ };
+
+ @Override
+ public DependencyResolver emptyDependencyResolver() {
+ return EMPTY_DEPENDENCY_RESOLVER;
+ }
}
diff --git a/compatibility/5.1/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_51/StorageEngineProxyImpl.java b/compatibility/5.1/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_51/StorageEngineProxyImpl.java
index 532768751cd..df302f95b11 100644
--- a/compatibility/5.1/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_51/StorageEngineProxyImpl.java
+++ b/compatibility/5.1/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_51/StorageEngineProxyImpl.java
@@ -22,7 +22,6 @@
import org.neo4j.common.Edition;
import org.neo4j.configuration.Config;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
-import org.neo4j.counts.CountsAccessor;
import org.neo4j.dbms.api.DatabaseManagementService;
import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
@@ -35,15 +34,12 @@
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
-import org.neo4j.internal.recordstorage.InMemoryStorageReader51;
import org.neo4j.io.layout.DatabaseLayout;
-import org.neo4j.storageengine.api.CommandCreationContext;
import org.neo4j.storageengine.api.PropertySelection;
import org.neo4j.storageengine.api.RelationshipSelection;
import org.neo4j.storageengine.api.StorageEngine;
import org.neo4j.storageengine.api.StorageEntityCursor;
import org.neo4j.storageengine.api.StoragePropertyCursor;
-import org.neo4j.storageengine.api.StorageReader;
import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
import org.neo4j.token.TokenHolders;
@@ -51,11 +47,6 @@
public class StorageEngineProxyImpl implements StorageEngineProxyApi {
- @Override
- public CommandCreationContext inMemoryCommandCreationContext() {
- return new InMemoryCommandCreationContextImpl();
- }
-
@Override
public void initRelationshipTraversalCursorForRelType(
StorageRelationshipTraversalCursor cursor,
@@ -69,13 +60,6 @@ public void initRelationshipTraversalCursorForRelType(
cursor.init(sourceNodeId, -1, relationshipSelection);
}
- @Override
- public StorageReader inMemoryStorageReader(
- CypherGraphStore graphStore, TokenHolders tokenHolders, CountsAccessor counts
- ) {
- return new InMemoryStorageReader51(graphStore, tokenHolders, counts);
- }
-
@Override
public StorageEngine createInMemoryStorageEngine(DatabaseLayout databaseLayout, TokenHolders tokenHolders) {
return new InMemoryStorageEngineImpl(databaseLayout, tokenHolders);
diff --git a/compatibility/5.10/neo4j-kernel-adapter/build.gradle b/compatibility/5.10/neo4j-kernel-adapter/build.gradle
new file mode 100644
index 00000000000..7b8bcc52246
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Neo4j Kernel Adapter 5.10'
+
+group = 'org.neo4j.gds'
+
+// for all 5.x versions
+if (ver.'neo4j'.startsWith('5.')) {
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java17']
+ }
+ }
+ }
+
+ dependencies {
+ annotationProcessor project(':annotations')
+ annotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.10'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+ compileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ compileOnly group: 'org.neo4j', name: 'annotations', version: neos.'5.10'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.10'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.10'
+ compileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.10'
+
+ implementation project(':neo4j-kernel-adapter-api')
+ }
+} else {
+ multiRelease {
+ targetVersions 11, 17
+ }
+
+ if (!project.hasProperty('no-forbidden-apis')) {
+ forbiddenApisJava17 {
+ exclude('**')
+ }
+ }
+
+ dependencies {
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ implementation project(':neo4j-kernel-adapter-api')
+
+ java17AnnotationProcessor project(':annotations')
+ java17AnnotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ java17AnnotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.10'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.10'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.10'
+ java17CompileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.10'
+ java17CompileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+
+ java17Implementation project(':neo4j-kernel-adapter-api')
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..119c57cae44
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ throw new UnsupportedOperationException("5.10 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.10 (placeholder)";
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..9a92eb7c201
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ throw new UnsupportedOperationException("5.10 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.10 (placeholder)";
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/BoltTransactionRunnerImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/BoltTransactionRunnerImpl.java
new file mode 100644
index 00000000000..c507ade6887
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/BoltTransactionRunnerImpl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.bolt.dbapi.BoltGraphDatabaseServiceSPI;
+import org.neo4j.bolt.dbapi.BoltTransaction;
+import org.neo4j.bolt.protocol.common.message.AccessMode;
+import org.neo4j.bolt.protocol.common.message.request.connection.RoutingContext;
+import org.neo4j.bolt.tx.statement.StatementQuerySubscriber;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.gds.compat.BoltQuerySubscriber;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.graphdb.QueryStatistics;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.QueryExecutionKernelException;
+import org.neo4j.values.virtual.MapValue;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+public class BoltTransactionRunnerImpl extends BoltTransactionRunner {
+
+ @Override
+ protected BoltQuerySubscriber boltQuerySubscriber() {
+ var subscriber = new StatementQuerySubscriber();
+ return new BoltQuerySubscriber<>() {
+ @Override
+ public void assertSucceeded() throws KernelException {
+ subscriber.assertSuccess();
+ }
+
+ @Override
+ public QueryStatistics queryStatistics() {
+ return subscriber.getStatistics();
+ }
+
+ @Override
+ public StatementQuerySubscriber innerSubscriber() {
+ return subscriber;
+ }
+ };
+ }
+
+ @Override
+ protected void executeQuery(
+ BoltTransaction boltTransaction,
+ String query,
+ MapValue parameters,
+ StatementQuerySubscriber querySubscriber
+ ) throws QueryExecutionKernelException {
+ boltTransaction.executeQuery(query, parameters, true, querySubscriber);
+ }
+
+ @Override
+ protected BoltTransaction beginBoltWriteTransaction(
+ BoltGraphDatabaseServiceSPI fabricDb,
+ LoginContext loginContext,
+ KernelTransaction.Type kernelTransactionType,
+ ClientConnectionInfo clientConnectionInfo,
+ List bookmarks,
+ Duration txTimeout,
+ Map txMetadata
+ ) {
+ return fabricDb.beginTransaction(
+ kernelTransactionType,
+ loginContext,
+ clientConnectionInfo,
+ bookmarks,
+ txTimeout,
+ AccessMode.WRITE,
+ txMetadata,
+ new RoutingContext(true, Map.of()),
+ QueryExecutionConfiguration.DEFAULT_CONFIG
+ );
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableProcedureImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableProcedureImpl.java
new file mode 100644
index 00000000000..b273fb43e8f
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableProcedureImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.collection.RawIterator;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.kernel.api.ResourceMonitor;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableProcedureImpl implements CallableProcedure {
+ private final CompatCallableProcedure procedure;
+
+ CallableProcedureImpl(CompatCallableProcedure procedure) {
+ this.procedure = procedure;
+ }
+
+ @Override
+ public ProcedureSignature signature() {
+ return this.procedure.signature();
+ }
+
+ @Override
+ public RawIterator apply(
+ Context ctx,
+ AnyValue[] input,
+ ResourceMonitor resourceMonitor
+ ) throws ProcedureException {
+ return this.procedure.apply(ctx, input);
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableUserAggregationFunctionImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableUserAggregationFunctionImpl.java
new file mode 100644
index 00000000000..d120d4b8314
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CallableUserAggregationFunctionImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompatUserAggregator;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.UserAggregationReducer;
+import org.neo4j.internal.kernel.api.procs.UserAggregationUpdater;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableUserAggregationFunctionImpl implements CallableUserAggregationFunction {
+ private final CompatUserAggregationFunction function;
+
+ CallableUserAggregationFunctionImpl(CompatUserAggregationFunction function) {
+ this.function = function;
+ }
+
+ @Override
+ public UserFunctionSignature signature() {
+ return this.function.signature();
+ }
+
+ @Override
+ public UserAggregationReducer createReducer(Context ctx) throws ProcedureException {
+ return new UserAggregatorImpl(this.function.create(ctx));
+ }
+
+ private static final class UserAggregatorImpl implements UserAggregationReducer, UserAggregationUpdater {
+ private final CompatUserAggregator aggregator;
+
+ private UserAggregatorImpl(CompatUserAggregator aggregator) {
+ this.aggregator = aggregator;
+ }
+
+ @Override
+ public UserAggregationUpdater newUpdater() {
+ return this;
+ }
+
+ @Override
+ public void update(AnyValue[] input) throws ProcedureException {
+ this.aggregator.update(input);
+ }
+
+ @Override
+ public void applyUpdates() {
+ }
+
+ @Override
+ public AnyValue result() throws ProcedureException {
+ return this.aggregator.result();
+ }
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatAccessModeImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatAccessModeImpl.java
new file mode 100644
index 00000000000..2152447a12b
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatAccessModeImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.CompatAccessMode;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.internal.kernel.api.RelTypeSupplier;
+import org.neo4j.internal.kernel.api.TokenSet;
+
+import java.util.function.Supplier;
+
+public final class CompatAccessModeImpl extends CompatAccessMode {
+
+ CompatAccessModeImpl(CustomAccessMode custom) {
+ super(custom);
+ }
+
+ @Override
+ public boolean allowsReadNodeProperty(Supplier labels, int propertyKey) {
+ return custom.allowsReadNodeProperty(propertyKey);
+ }
+
+ @Override
+ public boolean allowsReadRelationshipProperty(RelTypeSupplier relType, int propertyKey) {
+ return custom.allowsReadRelationshipProperty(propertyKey);
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatGraphDatabaseAPIImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatGraphDatabaseAPIImpl.java
new file mode 100644
index 00000000000..c7c19eda5ed
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatGraphDatabaseAPIImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.exceptions.Status;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.coreapi.TransactionExceptionMapper;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+final class CompatGraphDatabaseAPIImpl extends GdsGraphDatabaseAPI {
+
+ CompatGraphDatabaseAPIImpl(DatabaseManagementService dbms) {
+ super(dbms);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return api.isAvailable();
+ }
+
+ @Override
+ public TopologyGraphDbmsModel.HostedOnMode mode() {
+ // NOTE: This means we can never start clusters locally, which is probably fine since:
+ // 1) We never did this before
+ // 2) We only use this for tests and benchmarks
+ return TopologyGraphDbmsModel.HostedOnMode.SINGLE;
+ }
+
+ @Override
+ public InternalTransaction beginTransaction(
+ KernelTransaction.Type type,
+ LoginContext loginContext,
+ ClientConnectionInfo clientInfo,
+ long timeout,
+ TimeUnit unit,
+ Consumer terminationCallback,
+ TransactionExceptionMapper transactionExceptionMapper
+ ) {
+ return api.beginTransaction(
+ type,
+ loginContext,
+ clientInfo,
+ timeout,
+ unit,
+ terminationCallback,
+ transactionExceptionMapper
+ );
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatIndexQueryImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatIndexQueryImpl.java
new file mode 100644
index 00000000000..35211b88555
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatIndexQueryImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+
+final class CompatIndexQueryImpl implements CompatIndexQuery {
+ final PropertyIndexQuery indexQuery;
+
+ CompatIndexQueryImpl(PropertyIndexQuery indexQuery) {
+ this.indexQuery = indexQuery;
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatUsernameAuthSubjectImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatUsernameAuthSubjectImpl.java
new file mode 100644
index 00000000000..d4521de6ed4
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompatUsernameAuthSubjectImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.CompatUsernameAuthSubject;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+
+final class CompatUsernameAuthSubjectImpl extends CompatUsernameAuthSubject {
+
+ CompatUsernameAuthSubjectImpl(String username, AuthSubject authSubject) {
+ super(username, authSubject);
+ }
+
+ @Override
+ public String executingUser() {
+ return username;
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompositeNodeCursorImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompositeNodeCursorImpl.java
new file mode 100644
index 00000000000..95fab00f468
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/CompositeNodeCursorImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+
+import java.util.List;
+
+public final class CompositeNodeCursorImpl extends CompositeNodeCursor {
+
+ CompositeNodeCursorImpl(List cursors, int[] labelIds) {
+ super(cursors, labelIds);
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseLayoutImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseLayoutImpl.java
new file mode 100644
index 00000000000..e656e8bc798
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseLayoutImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.io.layout.DatabaseLayout;
+
+import java.nio.file.Path;
+
+public class GdsDatabaseLayoutImpl implements GdsDatabaseLayout {
+ private final DatabaseLayout databaseLayout;
+
+ public GdsDatabaseLayoutImpl(DatabaseLayout databaseLayout) {this.databaseLayout = databaseLayout;}
+
+ @Override
+ public Path databaseDirectory() {
+ return databaseLayout.databaseDirectory();
+ }
+
+ @Override
+ public Path getTransactionLogsDirectory() {
+ return databaseLayout.getTransactionLogsDirectory();
+ }
+
+ @Override
+ public Path metadataStore() {
+ return databaseLayout.metadataStore();
+ }
+
+ public DatabaseLayout databaseLayout() {
+ return databaseLayout;
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseManagementServiceBuilderImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseManagementServiceBuilderImpl.java
new file mode 100644
index 00000000000..3fd29287f7a
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/GdsDatabaseManagementServiceBuilderImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.api.DatabaseManagementServiceBuilderImplementation;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.graphdb.config.Setting;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+public class GdsDatabaseManagementServiceBuilderImpl implements GdsDatabaseManagementServiceBuilder {
+
+ private final DatabaseManagementServiceBuilderImplementation dbmsBuilder;
+
+ GdsDatabaseManagementServiceBuilderImpl(Path storeDir) {
+ this.dbmsBuilder = new DatabaseManagementServiceBuilderImplementation(storeDir);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfigRaw(Map configMap) {
+ dbmsBuilder.setConfigRaw(configMap);
+ return this;
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfig(Setting setting, S value) {
+ dbmsBuilder.setConfig(setting, value);
+ return this;
+ }
+
+ @Override
+ public DatabaseManagementService build() {
+ return dbmsBuilder.build();
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..f60c8eda563
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_10;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ return new Neo4jProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.10";
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyImpl.java
new file mode 100644
index 00000000000..63b70196011
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/Neo4jProxyImpl.java
@@ -0,0 +1,968 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.neo4j.common.DependencyResolver;
+import org.neo4j.common.EntityType;
+import org.neo4j.configuration.BootloaderSettings;
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.GraphDatabaseSettings;
+import org.neo4j.configuration.SettingValueParsers;
+import org.neo4j.configuration.connectors.ConnectorPortRegister;
+import org.neo4j.configuration.connectors.ConnectorType;
+import org.neo4j.configuration.helpers.DatabaseNameValidator;
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.fabric.FabricDatabaseManager;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.gds.compat.CompatExecutionMonitor;
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.gds.compat.CompatInput;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat.InputEntityIdVisitor;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.gds.compat.TestLog;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.internal.batchimport.AdditionalInitialIds;
+import org.neo4j.internal.batchimport.BatchImporter;
+import org.neo4j.internal.batchimport.BatchImporterFactory;
+import org.neo4j.internal.batchimport.Configuration;
+import org.neo4j.internal.batchimport.IndexConfig;
+import org.neo4j.internal.batchimport.InputIterable;
+import org.neo4j.internal.batchimport.Monitor;
+import org.neo4j.internal.batchimport.input.Collector;
+import org.neo4j.internal.batchimport.input.IdType;
+import org.neo4j.internal.batchimport.input.Input;
+import org.neo4j.internal.batchimport.input.InputEntityVisitor;
+import org.neo4j.internal.batchimport.input.PropertySizeCalculator;
+import org.neo4j.internal.batchimport.input.ReadableGroups;
+import org.neo4j.internal.batchimport.staging.ExecutionMonitor;
+import org.neo4j.internal.batchimport.staging.StageExecution;
+import org.neo4j.internal.helpers.HostnamePort;
+import org.neo4j.internal.id.IdGenerator;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.IndexQueryConstraints;
+import org.neo4j.internal.kernel.api.IndexReadSession;
+import org.neo4j.internal.kernel.api.NodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.NodeValueIndexCursor;
+import org.neo4j.internal.kernel.api.PropertyCursor;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+import org.neo4j.internal.kernel.api.QueryContext;
+import org.neo4j.internal.kernel.api.Read;
+import org.neo4j.internal.kernel.api.RelationshipScanCursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.internal.kernel.api.TokenPredicate;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.FieldSignature;
+import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.internal.kernel.api.procs.QualifiedName;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.internal.kernel.api.security.AccessMode;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+import org.neo4j.internal.kernel.api.security.SecurityContext;
+import org.neo4j.internal.recordstorage.RecordIdType;
+import org.neo4j.internal.schema.IndexCapability;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexOrder;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.layout.recordstorage.RecordDatabaseLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.context.EmptyVersionContextSupplier;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.KernelTransactionHandle;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
+import org.neo4j.kernel.database.NormalizedDatabaseName;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.index.schema.IndexImporterFactoryImpl;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.TransactionalContext;
+import org.neo4j.kernel.impl.query.TransactionalContextFactory;
+import org.neo4j.kernel.impl.store.RecordStore;
+import org.neo4j.kernel.impl.store.format.RecordFormatSelector;
+import org.neo4j.kernel.impl.store.format.RecordFormats;
+import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
+import org.neo4j.kernel.impl.transaction.log.EmptyLogTailMetadata;
+import org.neo4j.kernel.impl.transaction.log.files.TransactionLogInitializer;
+import org.neo4j.logging.Log;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.EmptyMemoryTracker;
+import org.neo4j.procedure.Mode;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.ssl.config.SslPolicyLoader;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.util.Bits;
+import org.neo4j.values.storable.TextArray;
+import org.neo4j.values.storable.ValueCategory;
+import org.neo4j.values.storable.Values;
+import org.neo4j.values.virtual.MapValue;
+import org.neo4j.values.virtual.NodeValue;
+import org.neo4j.values.virtual.VirtualValues;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.lang.String.format;
+import static org.neo4j.gds.compat.InternalReadOps.countByIdGenerator;
+import static org.neo4j.io.pagecache.context.EmptyVersionContextSupplier.EMPTY;
+
+public final class Neo4jProxyImpl implements Neo4jProxyApi {
+
+ @Override
+ public GdsGraphDatabaseAPI newDb(DatabaseManagementService dbms) {
+ return new CompatGraphDatabaseAPIImpl(dbms);
+ }
+
+ @Override
+ public String validateExternalDatabaseName(String databaseName) {
+ var normalizedName = new NormalizedDatabaseName(databaseName);
+ DatabaseNameValidator.validateExternalDatabaseName(normalizedName);
+ return normalizedName.name();
+ }
+
+ @Override
+ public AccessMode accessMode(CustomAccessMode customAccessMode) {
+ return new CompatAccessModeImpl(customAccessMode);
+ }
+
+ @Override
+ public String username(AuthSubject subject) {
+ return subject.executingUser();
+ }
+
+ @Override
+ public SecurityContext securityContext(
+ String username,
+ AuthSubject authSubject,
+ AccessMode mode,
+ String databaseName
+ ) {
+ return new SecurityContext(
+ new CompatUsernameAuthSubjectImpl(username, authSubject),
+ mode,
+ // GDS is always operating from an embedded context
+ ClientConnectionInfo.EMBEDDED_CONNECTION,
+ databaseName
+ );
+ }
+
+ @Override
+ public long getHighId(RecordStore extends AbstractBaseRecord> recordStore) {
+ return recordStore.getIdGenerator().getHighId();
+ }
+
+ @Override
+ public List> entityCursorScan(
+ KernelTransaction transaction,
+ int[] labelIds,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelIds);
+ } else {
+ var read = transaction.dataRead();
+ return Arrays
+ .stream(labelIds)
+ .mapToObj(read::nodeLabelScan)
+ .map(scan -> scanToStoreScan(scan, batchSize))
+ .collect(Collectors.toList());
+ }
+ }
+
+ @Override
+ public PropertyCursor allocatePropertyCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocatePropertyCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public PropertyReference propertyReference(NodeCursor nodeCursor) {
+ return ReferencePropertyReference.of(nodeCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference propertyReference(RelationshipScanCursor relationshipScanCursor) {
+ return ReferencePropertyReference.of(relationshipScanCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference noPropertyReference() {
+ return ReferencePropertyReference.empty();
+ }
+
+ @Override
+ public void nodeProperties(
+ KernelTransaction kernelTransaction,
+ long nodeReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .nodeProperties(nodeReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public void relationshipProperties(
+ KernelTransaction kernelTransaction,
+ long relationshipReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .relationshipProperties(relationshipReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public NodeCursor allocateNodeCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public RelationshipScanCursor allocateRelationshipScanCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateRelationshipScanCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeLabelIndexCursor allocateNodeLabelIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeLabelIndexCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeValueIndexCursor allocateNodeValueIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocateNodeValueIndexCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public boolean hasNodeLabelIndex(KernelTransaction kernelTransaction) {
+ return NodeLabelIndexLookupImpl.hasNodeLabelIndex(kernelTransaction);
+ }
+
+ @Override
+ public StoreScan nodeLabelIndexScan(
+ KernelTransaction transaction,
+ int labelId,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelId).get(0);
+ } else {
+ var read = transaction.dataRead();
+ return scanToStoreScan(read.nodeLabelScan(labelId), batchSize);
+ }
+ }
+
+ @Override
+ public StoreScan scanToStoreScan(Scan scan, int batchSize) {
+ return new ScanBasedStoreScanImpl<>(scan, batchSize);
+ }
+
+ private List> partitionedNodeLabelIndexScan(
+ KernelTransaction transaction,
+ int batchSize,
+ int... labelIds
+ ) {
+ var indexDescriptor = NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ );
+
+ if (indexDescriptor == IndexDescriptor.NO_INDEX) {
+ throw new IllegalStateException("There is no index that can back a node label scan.");
+ }
+
+ var read = transaction.dataRead();
+
+ // Our current strategy is to select the token with the highest count
+ // and use that one as the driving partitioned index scan. The partitions
+ // of all other partitioned index scans will be aligned to that one.
+ int maxToken = labelIds[0];
+ long maxCount = read.countsForNodeWithoutTxState(labelIds[0]);
+
+ for (int i = 1; i < labelIds.length; i++) {
+ long count = read.countsForNodeWithoutTxState(labelIds[i]);
+ if (count > maxCount) {
+ maxCount = count;
+ maxToken = labelIds[i];
+ }
+ }
+
+ int numberOfPartitions = PartitionedStoreScan.getNumberOfPartitions(maxCount, batchSize);
+
+ try {
+ var session = read.tokenReadSession(indexDescriptor);
+
+ var partitionedScan = read.nodeLabelScan(
+ session,
+ numberOfPartitions,
+ transaction.cursorContext(),
+ new TokenPredicate(maxToken)
+ );
+
+ var scans = new ArrayList>(labelIds.length);
+ scans.add(new PartitionedStoreScan(partitionedScan));
+
+ // Initialize the remaining index scans with the partitioning of the first scan.
+ for (int labelToken : labelIds) {
+ if (labelToken != maxToken) {
+ var scan = read.nodeLabelScan(session, partitionedScan, new TokenPredicate(labelToken));
+ scans.add(new PartitionedStoreScan(scan));
+ }
+ }
+
+ return scans;
+ } catch (KernelException e) {
+ // should not happen, we check for the index existence and applicability
+ // before reading it
+ throw new RuntimeException("Unexpected error while initialising reading from node label index", e);
+ }
+ }
+
+ @Override
+ public CompatIndexQuery rangeIndexQuery(
+ int propertyKeyId,
+ double from,
+ boolean fromInclusive,
+ double to,
+ boolean toInclusive
+ ) {
+ return new CompatIndexQueryImpl(PropertyIndexQuery.range(propertyKeyId, from, fromInclusive, to, toInclusive));
+ }
+
+ @Override
+ public CompatIndexQuery rangeAllIndexQuery(int propertyKeyId) {
+ var rangePredicate = PropertyIndexQuery.range(
+ propertyKeyId,
+ Values.doubleValue(Double.NEGATIVE_INFINITY),
+ true,
+ Values.doubleValue(Double.POSITIVE_INFINITY),
+ true
+ );
+ return new CompatIndexQueryImpl(rangePredicate);
+ }
+
+ @Override
+ public void nodeIndexSeek(
+ Read dataRead,
+ IndexReadSession index,
+ NodeValueIndexCursor cursor,
+ IndexOrder indexOrder,
+ boolean needsValues,
+ CompatIndexQuery query
+ ) throws KernelException {
+ var indexQueryConstraints = indexOrder == IndexOrder.NONE
+ ? IndexQueryConstraints.unordered(needsValues)
+ : IndexQueryConstraints.constrained(indexOrder, needsValues);
+
+ dataRead.nodeIndexSeek(
+ (QueryContext) dataRead,
+ index,
+ cursor,
+ indexQueryConstraints,
+ ((CompatIndexQueryImpl) query).indexQuery
+ );
+ }
+
+ @Override
+ public CompositeNodeCursor compositeNodeCursor(List cursors, int[] labelIds) {
+ return new CompositeNodeCursorImpl(cursors, labelIds);
+ }
+
+ @Override
+ public Configuration batchImporterConfig(
+ int batchSize,
+ int writeConcurrency,
+ Optional pageCacheMemory,
+ boolean highIO,
+ IndexConfig indexConfig
+ ) {
+ return new org.neo4j.internal.batchimport.Configuration() {
+ @Override
+ public int batchSize() {
+ return batchSize;
+ }
+
+ @Override
+ public int maxNumberOfWorkerThreads() {
+ return writeConcurrency;
+ }
+
+ @Override
+ public boolean highIO() {
+ return highIO;
+ }
+
+ @Override
+ public IndexConfig indexConfig() {
+ return indexConfig;
+ }
+ };
+ }
+
+ @Override
+ public int writeConcurrency(Configuration batchImportConfiguration) {
+ return batchImportConfiguration.maxNumberOfWorkerThreads();
+ }
+
+ @Override
+ public BatchImporter instantiateBatchImporter(
+ BatchImporterFactory factory,
+ GdsDatabaseLayout directoryStructure,
+ FileSystemAbstraction fileSystem,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ ExecutionMonitor executionMonitor,
+ AdditionalInitialIds additionalInitialIds,
+ Config dbConfig,
+ RecordFormats recordFormats,
+ JobScheduler jobScheduler,
+ Collector badCollector
+ ) {
+ dbConfig.set(GraphDatabaseSettings.db_format, recordFormats.name());
+ var databaseLayout = ((GdsDatabaseLayoutImpl) directoryStructure).databaseLayout();
+ return factory.instantiate(
+ databaseLayout,
+ fileSystem,
+ pageCacheTracer,
+ configuration,
+ logService,
+ executionMonitor,
+ additionalInitialIds,
+ new EmptyLogTailMetadata(dbConfig),
+ dbConfig,
+ Monitor.NO_MONITOR,
+ jobScheduler,
+ badCollector,
+ TransactionLogInitializer.getLogFilesInitializer(),
+ new IndexImporterFactoryImpl(),
+ EmptyMemoryTracker.INSTANCE,
+ new CursorContextFactory(PageCacheTracer.NULL, EmptyVersionContextSupplier.EMPTY)
+ );
+ }
+
+ @Override
+ public Input batchInputFrom(CompatInput compatInput) {
+ return new InputFromCompatInput(compatInput);
+ }
+
+ @Override
+ public InputEntityIdVisitor.Long inputEntityLongIdVisitor(IdType idType, ReadableGroups groups) {
+ switch (idType) {
+ case ACTUAL -> {
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id);
+ }
+ };
+ }
+ case INTEGER -> {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+ default -> throw new IllegalStateException("Unexpected value: " + idType);
+ }
+ }
+
+ @Override
+ public InputEntityIdVisitor.String inputEntityStringIdVisitor(ReadableGroups groups) {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.String() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, String id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, String id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, String id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+
+ @Override
+ public Setting additionalJvm() {
+ return BootloaderSettings.additional_jvm;
+ }
+
+ @Override
+ public Setting pageCacheMemory() {
+ return GraphDatabaseSettings.pagecache_memory;
+ }
+
+ @Override
+ public Long pageCacheMemoryValue(String value) {
+ return SettingValueParsers.BYTES.parse(value);
+ }
+
+ @Override
+ public ProcedureSignature procedureSignature(
+ QualifiedName name,
+ List inputSignature,
+ List outputSignature,
+ Mode mode,
+ boolean admin,
+ String deprecated,
+ String description,
+ String warning,
+ boolean eager,
+ boolean caseInsensitive,
+ boolean systemProcedure,
+ boolean internal,
+ boolean allowExpiredCredentials,
+ boolean threadSafe
+ ) {
+ return new ProcedureSignature(
+ name,
+ inputSignature,
+ outputSignature,
+ mode,
+ admin,
+ deprecated,
+ description,
+ warning,
+ eager,
+ caseInsensitive,
+ systemProcedure,
+ internal,
+ allowExpiredCredentials,
+ threadSafe
+ );
+ }
+
+ @Override
+ public long getHighestPossibleNodeCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.NODE).orElseGet(read::nodesGetCount);
+ }
+
+ @Override
+ public long getHighestPossibleRelationshipCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.RELATIONSHIP).orElseGet(read::relationshipsGetCount);
+ }
+
+ @Override
+ public String versionLongToString(long storeVersion) {
+ // copied from org.neo4j.kernel.impl.store.LegacyMetadataHandler.versionLongToString which is private
+ if (storeVersion == -1) {
+ return "Unknown";
+ }
+ Bits bits = Bits.bitsFromLongs(new long[]{storeVersion});
+ int length = bits.getShort(8);
+ if (length == 0 || length > 7) {
+ throw new IllegalArgumentException(format(Locale.ENGLISH, "The read version string length %d is not proper.", length));
+ }
+ char[] result = new char[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = (char) bits.getShort(8);
+ }
+ return new String(result);
+ }
+
+ private static final class InputFromCompatInput implements Input {
+ private final CompatInput delegate;
+
+ private InputFromCompatInput(CompatInput delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public InputIterable nodes(Collector badCollector) {
+ return delegate.nodes(badCollector);
+ }
+
+ @Override
+ public InputIterable relationships(Collector badCollector) {
+ return delegate.relationships(badCollector);
+ }
+
+ @Override
+ public IdType idType() {
+ return delegate.idType();
+ }
+
+ @Override
+ public ReadableGroups groups() {
+ return delegate.groups();
+ }
+
+ @Override
+ public Estimates calculateEstimates(PropertySizeCalculator propertySizeCalculator) throws IOException {
+ return delegate.calculateEstimates((values, kernelTransaction) -> propertySizeCalculator.calculateSize(
+ values,
+ kernelTransaction.cursorContext(),
+ kernelTransaction.memoryTracker()
+ ));
+ }
+ }
+
+ @Override
+ public TestLog testLog() {
+ return new TestLogImpl();
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getUserLog(LogService logService, Class> loggingClass) {
+ return logService.getUserLog(loggingClass);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getInternalLog(LogService logService, Class> loggingClass) {
+ return logService.getInternalLog(loggingClass);
+ }
+
+ @Override
+ public NodeValue nodeValue(long id, TextArray labels, MapValue properties) {
+ return VirtualValues.nodeValue(id, String.valueOf(id), labels, properties);
+ }
+
+ @Override
+ public Relationship virtualRelationship(long id, Node startNode, Node endNode, RelationshipType type) {
+ return new VirtualRelationshipImpl(id, startNode, endNode, type);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder databaseManagementServiceBuilder(Path storeDir) {
+ return new GdsDatabaseManagementServiceBuilderImpl(storeDir);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats selectRecordFormatForStore(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ return RecordFormatSelector.selectForStore(
+ (RecordDatabaseLayout) databaseLayout,
+ fs,
+ pageCache,
+ logService.getInternalLogProvider(),
+ new CursorContextFactory(pageCacheTracer, EMPTY)
+ );
+ }
+
+ @Override
+ public boolean isNotNumericIndex(IndexCapability indexCapability) {
+ return !indexCapability.areValueCategoriesAccepted(ValueCategory.NUMBER);
+ }
+
+ @Override
+ public void setAllowUpgrades(Config.Builder configBuilder, boolean value) {
+ }
+
+ @Override
+ public String defaultRecordFormatSetting() {
+ return GraphDatabaseSettings.db_format.defaultValue();
+ }
+
+ @Override
+ public void configureRecordFormat(Config.Builder configBuilder, String recordFormat) {
+ var databaseRecordFormat = recordFormat.toLowerCase(Locale.ENGLISH);
+ configBuilder.set(GraphDatabaseSettings.db_format, databaseRecordFormat);
+ }
+
+ @Override
+ public GdsDatabaseLayout databaseLayout(Config config, String databaseName) {
+ var storageEngineFactory = StorageEngineFactory.selectStorageEngine(config);
+ var dbLayout = neo4jLayout(config).databaseLayout(databaseName);
+ var databaseLayout = storageEngineFactory.formatSpecificDatabaseLayout(dbLayout);
+ return new GdsDatabaseLayoutImpl(databaseLayout);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Neo4jLayout neo4jLayout(Config config) {
+ return Neo4jLayout.of(config);
+ }
+
+ @Override
+ public BoltTransactionRunner, ?> boltTransactionRunner() {
+ return new BoltTransactionRunnerImpl();
+ }
+
+ @Override
+ public HostnamePort getLocalBoltAddress(ConnectorPortRegister connectorPortRegister) {
+ return connectorPortRegister.getLocalAddress(ConnectorType.BOLT);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public SslPolicyLoader createSllPolicyLoader(
+ FileSystemAbstraction fileSystem,
+ Config config,
+ LogService logService
+ ) {
+ return SslPolicyLoader.create(fileSystem, config, logService.getInternalLogProvider());
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats recordFormatSelector(
+ String databaseName,
+ Config databaseConfig,
+ FileSystemAbstraction fs,
+ LogService logService,
+ GraphDatabaseService databaseService
+ ) {
+ var neo4jLayout = Neo4jLayout.of(databaseConfig);
+ var recordDatabaseLayout = RecordDatabaseLayout.of(neo4jLayout, databaseName);
+ return RecordFormatSelector.selectForStoreOrConfigForNewDbs(
+ databaseConfig,
+ recordDatabaseLayout,
+ fs,
+ GraphDatabaseApiProxy.resolveDependency(databaseService, PageCache.class),
+ logService.getInternalLogProvider(),
+ GraphDatabaseApiProxy.resolveDependency(databaseService, CursorContextFactory.class)
+ );
+ }
+
+ @Override
+ public ExecutionMonitor executionMonitor(CompatExecutionMonitor compatExecutionMonitor) {
+ return new ExecutionMonitor.Adapter(
+ compatExecutionMonitor.checkIntervalMillis(),
+ TimeUnit.MILLISECONDS
+ ) {
+
+ @Override
+ public void initialize(DependencyResolver dependencyResolver) {
+ compatExecutionMonitor.initialize(dependencyResolver);
+ }
+
+ @Override
+ public void start(StageExecution execution) {
+ compatExecutionMonitor.start(execution);
+ }
+
+ @Override
+ public void end(StageExecution execution, long totalTimeMillis) {
+ compatExecutionMonitor.end(execution, totalTimeMillis);
+ }
+
+ @Override
+ public void done(boolean successful, long totalTimeMillis, String additionalInformation) {
+ compatExecutionMonitor.done(successful, totalTimeMillis, additionalInformation);
+ }
+
+ @Override
+ public void check(StageExecution execution) {
+ compatExecutionMonitor.check(execution);
+ }
+ };
+ }
+
+ @Override
+ @SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE") // We assign nulls because it makes the code more readable
+ public UserFunctionSignature userFunctionSignature(
+ QualifiedName name,
+ List inputSignature,
+ Neo4jTypes.AnyType type,
+ String description,
+ boolean internal,
+ boolean threadSafe,
+ Optional deprecatedBy
+ ) {
+ String category = null; // No predefined categpry (like temporal or math)
+ var caseInsensitive = false; // case sensitive name match
+ var isBuiltIn = false; // is built in; never true for GDS
+
+ return new UserFunctionSignature(
+ name,
+ inputSignature,
+ type,
+ deprecatedBy.orElse(null),
+ description,
+ category,
+ caseInsensitive,
+ isBuiltIn,
+ internal,
+ threadSafe
+ );
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableProcedure callableProcedure(CompatCallableProcedure procedure) {
+ return new CallableProcedureImpl(procedure);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableUserAggregationFunction callableUserAggregationFunction(CompatUserAggregationFunction function) {
+ return new CallableUserAggregationFunctionImpl(function);
+ }
+
+ @Override
+ public long transactionId(KernelTransactionHandle kernelTransactionHandle) {
+ return kernelTransactionHandle.getTransactionSequenceNumber();
+ }
+
+ @Override
+ public void reserveNeo4jIds(IdGeneratorFactory generatorFactory, int size, CursorContext cursorContext) {
+ IdGenerator idGenerator = generatorFactory.get(RecordIdType.NODE);
+
+ idGenerator.nextConsecutiveIdRange(size, false, cursorContext);
+ }
+
+ @Override
+ public TransactionalContext newQueryContext(
+ TransactionalContextFactory contextFactory,
+ InternalTransaction tx,
+ String queryText,
+ MapValue queryParameters
+ ) {
+ return contextFactory.newContext(tx, queryText, queryParameters, QueryExecutionConfiguration.DEFAULT_CONFIG);
+ }
+
+ @Override
+ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
+ var databaseManager = GraphDatabaseApiProxy.resolveDependency(databaseService, FabricDatabaseManager.class);
+ return databaseManager.isFabricDatabase(GraphDatabaseApiProxy.databaseId(databaseService));
+ }
+
+ @Override
+ public T lookupComponentProvider(Context ctx, Class component, boolean safe) throws ProcedureException {
+ var globalProcedures = GraphDatabaseApiProxy.resolveDependency(ctx.dependencyResolver(), GlobalProcedures.class);
+ return globalProcedures.lookupComponentProvider(component, safe).apply(ctx);
+ }
+
+ @Override
+ public GlobalProcedureRegistry globalProcedureRegistry(GlobalProcedures globalProcedures) {
+ return new GlobalProcedureRegistry() {
+ @Override
+ public Set getAllProcedures() {
+ return globalProcedures.getAllProcedures();
+ }
+
+ @Override
+ public Stream getAllNonAggregatingFunctions() {
+ return globalProcedures.getAllNonAggregatingFunctions();
+ }
+
+ @Override
+ public Stream getAllAggregatingFunctions() {
+ return globalProcedures.getAllAggregatingFunctions();
+ }
+ };
+ }
+
+ private static final DependencyResolver EMPTY_DEPENDENCY_RESOLVER = new DependencyResolver.Adapter() {
+ @Override
+ public T resolveDependency(Class type, SelectionStrategy selector) {
+ return null;
+ }
+
+ @Override
+ public boolean containsDependency(Class> type) {
+ return false;
+ }
+ };
+
+ @Override
+ public DependencyResolver emptyDependencyResolver() {
+ return EMPTY_DEPENDENCY_RESOLVER;
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/NodeLabelIndexLookupImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/NodeLabelIndexLookupImpl.java
new file mode 100644
index 00000000000..aaf6b0ee05e
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/NodeLabelIndexLookupImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.common.EntityType;
+import org.neo4j.internal.kernel.api.InternalIndexState;
+import org.neo4j.internal.kernel.api.SchemaRead;
+import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexType;
+import org.neo4j.internal.schema.SchemaDescriptor;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class NodeLabelIndexLookupImpl {
+
+ static boolean hasNodeLabelIndex(KernelTransaction transaction) {
+ return NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ ) != IndexDescriptor.NO_INDEX;
+ }
+
+ static IndexDescriptor findUsableMatchingIndex(
+ KernelTransaction transaction,
+ SchemaDescriptor schemaDescriptor
+ ) {
+ var schemaRead = transaction.schemaRead();
+ var iterator = schemaRead.index(schemaDescriptor);
+ while (iterator.hasNext()) {
+ var index = iterator.next();
+ if (index.getIndexType() == IndexType.LOOKUP && indexIsOnline(schemaRead, index)) {
+ return index;
+ }
+ }
+ return IndexDescriptor.NO_INDEX;
+ }
+
+ private static boolean indexIsOnline(SchemaRead schemaRead, IndexDescriptor index) {
+ var state = InternalIndexState.FAILED;
+ try {
+ state = schemaRead.indexGetState(index);
+ } catch (IndexNotFoundKernelException e) {
+ // Well the index should always exist here, but if we didn't find it while checking the state,
+ // then we obviously don't want to use it.
+ }
+ return state == InternalIndexState.ONLINE;
+ }
+
+ private NodeLabelIndexLookupImpl() {}
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/PartitionedStoreScan.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/PartitionedStoreScan.java
new file mode 100644
index 00000000000..5d542426fd6
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/PartitionedStoreScan.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.PartitionedScan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class PartitionedStoreScan implements StoreScan {
+ private final PartitionedScan scan;
+
+ PartitionedStoreScan(PartitionedScan scan) {
+ this.scan = scan;
+ }
+
+ static int getNumberOfPartitions(long nodeCount, int batchSize) {
+ int numberOfPartitions;
+ if (nodeCount > 0) {
+ // ceil div to try to get enough partitions so a single one does
+ // not include more nodes than batchSize
+ long partitions = ((nodeCount - 1) / batchSize) + 1;
+
+ // value must be positive
+ if (partitions < 1) {
+ partitions = 1;
+ }
+
+ numberOfPartitions = (int) Long.min(Integer.MAX_VALUE, partitions);
+ } else {
+ // we have no partitions to scan, but the value must still be positive
+ numberOfPartitions = 1;
+ }
+ return numberOfPartitions;
+ }
+
+ @Override
+ public boolean reserveBatch(NodeLabelIndexCursor cursor, KernelTransaction ktx) {
+ return scan.reservePartition(cursor, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ReferencePropertyReference.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ReferencePropertyReference.java
new file mode 100644
index 00000000000..c94d0d621dd
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ReferencePropertyReference.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.storageengine.api.Reference;
+
+import java.util.Objects;
+
+public final class ReferencePropertyReference implements PropertyReference {
+
+ private static final PropertyReference EMPTY = new ReferencePropertyReference(null);
+
+ public final Reference reference;
+
+ private ReferencePropertyReference(Reference reference) {
+ this.reference = reference;
+ }
+
+ public static PropertyReference of(Reference reference) {
+ return new ReferencePropertyReference(Objects.requireNonNull(reference));
+ }
+
+ public static PropertyReference empty() {
+ return EMPTY;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return reference == null;
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ScanBasedStoreScanImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ScanBasedStoreScanImpl.java
new file mode 100644
index 00000000000..f26affc5f05
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/ScanBasedStoreScanImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+public final class ScanBasedStoreScanImpl implements StoreScan {
+ private final Scan scan;
+ private final int batchSize;
+
+ public ScanBasedStoreScanImpl(Scan scan, int batchSize) {
+ this.scan = scan;
+ this.batchSize = batchSize;
+ }
+
+ @Override
+ public boolean reserveBatch(C cursor, KernelTransaction ktx) {
+ return scan.reserveBatch(cursor, batchSize, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..69239b3098d
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_10;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ return new SettingProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.10";
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyImpl.java
new file mode 100644
index 00000000000..26ca820cefc
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/SettingProxyImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.SettingBuilder;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.DatabaseMode;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.kernel.impl.factory.GraphDatabaseFacade;
+import org.neo4j.kernel.internal.GraphDatabaseAPI;
+
+public class SettingProxyImpl implements SettingProxyApi {
+
+ @Override
+ public Setting setting(org.neo4j.gds.compat.Setting setting) {
+ var builder = SettingBuilder.newBuilder(setting.name(), setting.parser(), setting.defaultValue());
+ if (setting.dynamic()) {
+ builder = builder.dynamic();
+ }
+ if (setting.immutable()) {
+ builder = builder.immutable();
+ }
+ setting.dependency().ifPresent(builder::setDependency);
+ setting.constraints().forEach(builder::addConstraint);
+ return builder.build();
+ }
+
+ @Override
+ public DatabaseMode databaseMode(Config config, GraphDatabaseService databaseService) {
+ return switch (((GraphDatabaseAPI) databaseService).mode()) {
+ case RAFT -> DatabaseMode.CORE;
+ case REPLICA -> DatabaseMode.READ_REPLICA;
+ case SINGLE -> DatabaseMode.SINGLE;
+ case VIRTUAL -> throw new UnsupportedOperationException("What's a virtual database anyway?");
+ };
+ }
+
+ @Override
+ public void setDatabaseMode(Config config, DatabaseMode databaseMode, GraphDatabaseService databaseService) {
+ // super hacky, there is no way to set the mode of a database without restarting it
+ if (!(databaseService instanceof GraphDatabaseFacade db)) {
+ throw new IllegalArgumentException(
+ "Cannot set database mode on a database that is not a GraphDatabaseFacade");
+ }
+ try {
+ var modeField = GraphDatabaseFacade.class.getDeclaredField("mode");
+ modeField.setAccessible(true);
+ modeField.set(db, switch (databaseMode) {
+ case CORE -> TopologyGraphDbmsModel.HostedOnMode.RAFT;
+ case READ_REPLICA -> TopologyGraphDbmsModel.HostedOnMode.REPLICA;
+ case SINGLE -> TopologyGraphDbmsModel.HostedOnMode.SINGLE;
+ });
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(
+ "Could not set the mode field because it no longer exists. This compat layer needs to be updated.",
+ e
+ );
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Could not get the permissions to set the mode field.", e);
+ }
+ }
+
+ @Override
+ public String secondaryModeName() {
+ return "Secondary";
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/TestLogImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/TestLogImpl.java
new file mode 100644
index 00000000000..cd67346d60c
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/TestLogImpl.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.TestLog;
+
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+public class TestLogImpl implements TestLog {
+
+ private final ConcurrentMap> messages;
+
+ TestLogImpl() {
+ messages = new ConcurrentHashMap<>(3);
+ }
+
+ @Override
+ public void assertContainsMessage(String level, String fragment) {
+ if (!containsMessage(level, fragment)) {
+ throw new RuntimeException(
+ String.format(
+ Locale.US,
+ "Expected log output to contain `%s` for log level `%s`%nLog messages:%n%s",
+ fragment,
+ level,
+ String.join("\n", messages.get(level))
+ )
+ );
+ }
+ }
+
+ @Override
+ public boolean containsMessage(String level, String fragment) {
+ ConcurrentLinkedQueue messageList = messages.getOrDefault(level, new ConcurrentLinkedQueue<>());
+ return messageList.stream().anyMatch((message) -> message.contains(fragment));
+ }
+
+ @Override
+ public boolean hasMessages(String level) {
+ return !messages.getOrDefault(level, new ConcurrentLinkedQueue<>()).isEmpty();
+ }
+
+ @Override
+ public ArrayList getMessages(String level) {
+ return new ArrayList<>(messages.getOrDefault(level, new ConcurrentLinkedQueue<>()));
+ }
+
+ @SuppressForbidden(reason = "test log can print")
+ public void printMessages() {
+ System.out.println("TestLog Messages: " + messages);
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return true;
+ }
+
+ @Override
+ public void debug(String message) {
+ logMessage(DEBUG, message);
+ }
+
+ @Override
+ public void debug(String message, Throwable throwable) {
+ debug(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void debug(String format, Object... arguments) {
+ debug(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void info(String message) {
+ logMessage(INFO, message);
+ }
+
+ @Override
+ public void info(String message, Throwable throwable) {
+ info(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void info(String format, Object... arguments) {
+ info(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void warn(String message) {
+ logMessage(WARN, message);
+ }
+
+ @Override
+ public void warn(String message, Throwable throwable) {
+ warn(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void warn(String format, Object... arguments) {
+ warn(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void error(String message) {
+ logMessage(ERROR, message);
+ }
+
+ @Override
+ public void error(String message, Throwable throwable) {
+ error(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void error(String format, Object... arguments) {
+ error(String.format(Locale.US, format, arguments));
+ }
+
+ private void logMessage(String level, String message) {
+ messages.computeIfAbsent(
+ level,
+ (ignore) -> new ConcurrentLinkedQueue<>()
+ ).add(message);
+ }
+}
diff --git a/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/VirtualRelationshipImpl.java b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/VirtualRelationshipImpl.java
new file mode 100644
index 00000000000..d7a9c41076f
--- /dev/null
+++ b/compatibility/5.10/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_510/VirtualRelationshipImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.VirtualRelationship;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.RelationshipType;
+
+public class VirtualRelationshipImpl extends VirtualRelationship {
+
+ VirtualRelationshipImpl(
+ long id,
+ Node startNode,
+ Node endNode,
+ RelationshipType type
+ ) {
+ super(id, startNode, endNode, type);
+ }
+
+ @Override
+ public String getElementId() {
+ return Long.toString(getId());
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/build.gradle b/compatibility/5.10/storage-engine-adapter/build.gradle
new file mode 100644
index 00000000000..4ab26345d26
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/build.gradle
@@ -0,0 +1,68 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Storage Engine Adapter 5.10'
+
+group = 'org.neo4j.gds'
+
+// for all 5.x versions
+if (ver.'neo4j'.startsWith('5.')) {
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java17']
+ }
+ }
+ }
+
+ dependencies {
+ annotationProcessor project(':annotations')
+ annotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.10'
+
+ compileOnly project(':annotations')
+ compileOnly project(':progress-tracking')
+ compileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.10'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.10'
+
+ implementation project(':core')
+ implementation project(':storage-engine-adapter-api')
+ implementation project(':config-api')
+ implementation project(':string-formatting')
+ }
+} else {
+ multiRelease {
+ targetVersions 11, 17
+ }
+
+ if (!project.hasProperty('no-forbidden-apis')) {
+ forbiddenApisJava17 {
+ exclude('**')
+ }
+ }
+
+ dependencies {
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+ compileOnly group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+ compileOnly group: 'org.neo4j', name: 'neo4j-kernel-api', version: ver.'neo4j'
+
+ implementation project(':neo4j-adapter')
+ implementation project(':storage-engine-adapter-api')
+
+ java17AnnotationProcessor project(':annotations')
+ java17AnnotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ java17AnnotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.10'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly project(':progress-tracking')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.10'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.10'
+
+ java17Implementation project(':core')
+ java17Implementation project(':storage-engine-adapter-api')
+ java17Implementation project(':config-api')
+ java17Implementation project(':string-formatting')
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java b/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java
new file mode 100644
index 00000000000..ec941c14b1e
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.configuration.Config;
+import org.neo4j.dbms.database.readonly.DatabaseReadOnlyChecker;
+import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
+import org.neo4j.internal.id.IdController;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.schema.IndexConfigCompleter;
+import org.neo4j.internal.schema.SchemaRule;
+import org.neo4j.internal.schema.SchemaState;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.lock.LockService;
+import org.neo4j.logging.LogProvider;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.monitoring.DatabaseHealth;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+import org.neo4j.storageengine.api.ConstraintRuleAccessor;
+import org.neo4j.storageengine.api.LogVersionRepository;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageFilesState;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.TransactionIdStore;
+import org.neo4j.storageengine.migration.RollingUpgradeCompatibility;
+import org.neo4j.storageengine.migration.SchemaRuleMigrationAccess;
+import org.neo4j.storageengine.migration.StoreMigrationParticipant;
+import org.neo4j.token.TokenHolders;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+@ServiceProvider
+public class InMemoryStorageEngineFactory implements StorageEngineFactory {
+
+ @Override
+ public String name() {
+ return "unsupported510";
+ }
+
+ @Override
+ public StoreVersionCheck versionCheck(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(String storeVersion) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(StoreId storeId) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public RollingUpgradeCompatibility rollingUpgradeCompatibility() {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public List migrationParticipants(
+ FileSystemAbstraction fs,
+ Config config,
+ PageCache pageCache,
+ JobScheduler jobScheduler,
+ LogService logService,
+ PageCacheTracer cacheTracer,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public StorageEngine instantiate(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ TokenHolders tokenHolders,
+ SchemaState schemaState,
+ ConstraintRuleAccessor constraintSemantics,
+ IndexConfigCompleter indexConfigCompleter,
+ LockService lockService,
+ IdGeneratorFactory idGeneratorFactory,
+ IdController idController,
+ DatabaseHealth databaseHealth,
+ LogProvider internalLogProvider,
+ LogProvider userLogProvider,
+ RecoveryCleanupWorkCollector recoveryCleanupWorkCollector,
+ PageCacheTracer cacheTracer,
+ boolean createStoreIfNotExists,
+ DatabaseReadOnlyChecker readOnlyChecker,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public List listStorageFiles(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout) throws
+ IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public boolean storageExists(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout, PageCache pageCache) {
+ return false;
+ }
+
+ @Override
+ public TransactionIdStore readOnlyTransactionIdStore(
+ FileSystemAbstraction filySystem,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public LogVersionRepository readOnlyLogVersionRepository(
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public MetadataProvider transactionMetaDataStore(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ PageCacheTracer cacheTracer,
+ DatabaseReadOnlyChecker readOnlyChecker
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreId storeId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public void setStoreId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext,
+ StoreId storeId,
+ long upgradeTxChecksum,
+ long upgradeTxCommitTimestamp
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public void setExternalStoreUUID(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext,
+ UUID externalStoreId
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public Optional databaseIdUuid(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public SchemaRuleMigrationAccess schemaRuleMigrationAccess(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ Config config,
+ DatabaseLayout databaseLayout,
+ LogService logService,
+ String recordFormats,
+ PageCacheTracer cacheTracer,
+ CursorContext cursorContext,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public List loadSchemaRules(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public StorageFilesState checkStoreFileState(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache
+ ) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public CommandReaderFactory commandReaderFactory() {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public DatabaseLayout databaseLayout(Neo4jLayout neo4jLayout, String databaseName) {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 00000000000..6267c704fec
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.compat.StorageEngineProxyFactory;
+
+@ServiceProvider
+public class StorageEngineProxyFactoryImpl implements StorageEngineProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public StorageEngineProxyApi load() {
+ throw new UnsupportedOperationException("5.10 storage engine requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.10";
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCommandCreationContextImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCommandCreationContextImpl.java
new file mode 100644
index 00000000000..74582802065
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCommandCreationContextImpl.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.kernel.KernelVersionProvider;
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.storageengine.api.CommandCreationContext;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+
+public class InMemoryCommandCreationContextImpl implements CommandCreationContext {
+
+ private final AtomicLong schemaTokens;
+ private final AtomicInteger propertyTokens;
+ private final AtomicInteger labelTokens;
+ private final AtomicInteger typeTokens;
+
+ InMemoryCommandCreationContextImpl() {
+ this.schemaTokens = new AtomicLong(0);
+ this.propertyTokens = new AtomicInteger(0);
+ this.labelTokens = new AtomicInteger(0);
+ this.typeTokens = new AtomicInteger(0);
+ }
+
+ @Override
+ public long reserveNode() {
+ throw new UnsupportedOperationException("Creating nodes is not supported");
+ }
+
+ @Override
+ public long reserveRelationship(
+ long sourceNode,
+ long targetNode,
+ int relationshipType,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ throw new UnsupportedOperationException("Creating relationships is not supported");
+ }
+
+ @Override
+ public long reserveSchema() {
+ return schemaTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reserveLabelTokenId() {
+ return labelTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reservePropertyKeyTokenId() {
+ return propertyTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reserveRelationshipTypeTokenId() {
+ return typeTokens.getAndIncrement();
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void initialize(
+ KernelVersionProvider kernelVersionProvider,
+ CursorContext cursorContext,
+ StoreCursors storeCursors,
+ Supplier oldestActiveTransactionSequenceNumber,
+ ResourceLocker locks,
+ Supplier lockTracer
+ ) {
+
+ }
+
+ @Override
+ public KernelVersion kernelVersion() {
+ // NOTE: Double-check if this is still correct when you copy this into a new compat layer
+ return KernelVersion.getLatestVersion(Config.newBuilder().build());
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCountsStoreImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCountsStoreImpl.java
new file mode 100644
index 00000000000..1d31cd83d7a
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryCountsStoreImpl.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.documented.ReporterFactory;
+import org.neo4j.counts.CountsAccessor;
+import org.neo4j.counts.CountsStorage;
+import org.neo4j.counts.CountsVisitor;
+import org.neo4j.gds.NodeLabel;
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.internal.helpers.progress.ProgressMonitorFactory;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.tracing.FileFlushEvent;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+import org.neo4j.token.TokenHolders;
+import org.neo4j.token.api.TokenNotFoundException;
+
+public class InMemoryCountsStoreImpl implements CountsStorage, CountsAccessor {
+
+ private final GraphStore graphStore;
+ private final TokenHolders tokenHolders;
+
+ public InMemoryCountsStoreImpl(
+ GraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+
+ this.graphStore = graphStore;
+ this.tokenHolders = tokenHolders;
+ }
+
+ @Override
+ public void start(
+ CursorContext cursorContext, StoreCursors storeCursors, MemoryTracker memoryTracker
+ ) {
+
+ }
+
+ @Override
+ public void checkpoint(FileFlushEvent fileFlushEvent, CursorContext cursorContext) {
+
+ }
+
+ @Override
+ public long nodeCount(int labelId, CursorContext cursorContext) {
+ if (labelId == -1) {
+ return graphStore.nodeCount();
+ }
+
+ String nodeLabel;
+ try {
+ nodeLabel = tokenHolders.labelTokens().getTokenById(labelId).name();
+ } catch (TokenNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return graphStore.nodes().nodeCount(NodeLabel.of(nodeLabel));
+ }
+
+ @Override
+ public long relationshipCount(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ // TODO: this is quite wrong
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public boolean consistencyCheck(
+ ReporterFactory reporterFactory,
+ CursorContextFactory contextFactory,
+ int numThreads,
+ ProgressMonitorFactory progressMonitorFactory
+ ) {
+ return true;
+ }
+
+ @Override
+ public CountsAccessor.Updater apply(long txId, boolean isLast, CursorContext cursorContext) {
+ throw new UnsupportedOperationException("Updates are not supported");
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void accept(CountsVisitor visitor, CursorContext cursorContext) {
+ tokenHolders.labelTokens().getAllTokens().forEach(labelToken -> {
+ visitor.visitNodeCount(labelToken.id(), nodeCount(labelToken.id(), cursorContext));
+ });
+
+ visitor.visitRelationshipCount(-1, -1, -1, graphStore.relationshipCount());
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryMetaDataProviderImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryMetaDataProviderImpl.java
new file mode 100644
index 00000000000..884eff2c379
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryMetaDataProviderImpl.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.internal.recordstorage.InMemoryLogVersionRepository510;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.TransactionIdSnapshot;
+import org.neo4j.storageengine.api.ClosedTransactionMetadata;
+import org.neo4j.storageengine.api.ExternalStoreId;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.TransactionId;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.UUID;
+
+public class InMemoryMetaDataProviderImpl implements MetadataProvider {
+
+ private final ExternalStoreId externalStoreId;
+ private final InMemoryLogVersionRepository510 logVersionRepository;
+ private final InMemoryTransactionIdStoreImpl transactionIdStore;
+
+ InMemoryMetaDataProviderImpl() {
+ this.logVersionRepository = new InMemoryLogVersionRepository510();
+ this.externalStoreId = new ExternalStoreId(UUID.randomUUID());
+ this.transactionIdStore = new InMemoryTransactionIdStoreImpl();
+ }
+
+ @Override
+ public ExternalStoreId getExternalStoreId() {
+ return this.externalStoreId;
+ }
+
+ @Override
+ public ClosedTransactionMetadata getLastClosedTransaction() {
+ return this.transactionIdStore.getLastClosedTransaction();
+ }
+
+ @Override
+ public void setCurrentLogVersion(long version) {
+ logVersionRepository.setCurrentLogVersion(version);
+ }
+
+ @Override
+ public long incrementAndGetVersion() {
+ return logVersionRepository.incrementAndGetVersion();
+ }
+
+ @Override
+ public void setCheckpointLogVersion(long version) {
+ logVersionRepository.setCheckpointLogVersion(version);
+ }
+
+ @Override
+ public long incrementAndGetCheckpointLogVersion() {
+ return logVersionRepository.incrementAndGetCheckpointLogVersion();
+ }
+
+ @Override
+ public void transactionCommitted(long transactionId, int checksum, long commitTimestamp, long consensusIndex) {
+ transactionIdStore.transactionCommitted(transactionId, checksum, commitTimestamp, consensusIndex);
+ }
+
+ @Override
+ public void setLastCommittedAndClosedTransactionId(
+ long transactionId,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex,
+ long byteOffset,
+ long logVersion
+ ) {
+ transactionIdStore.setLastCommittedAndClosedTransactionId(
+ transactionId,
+ checksum,
+ commitTimestamp,
+ consensusIndex,
+ byteOffset,
+ logVersion
+ );
+ }
+
+ @Override
+ public void transactionClosed(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.transactionIdStore.transactionClosed(
+ transactionId,
+ logVersion,
+ byteOffset,
+ checksum,
+ commitTimestamp,
+ consensusIndex
+ );
+ }
+
+ @Override
+ public void resetLastClosedTransaction(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.transactionIdStore.resetLastClosedTransaction(
+ transactionId,
+ logVersion,
+ byteOffset,
+ checksum,
+ commitTimestamp,
+ consensusIndex
+ );
+ }
+
+ @Override
+ public TransactionIdSnapshot getClosedTransactionSnapshot() {
+ return new TransactionIdSnapshot(this.getLastClosedTransactionId());
+ }
+
+ @Override
+ public void regenerateMetadata(StoreId storeId, UUID externalStoreUUID, CursorContext cursorContext) {
+ }
+
+ @Override
+ public StoreId getStoreId() {
+ return StoreId.UNKNOWN;
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public long getCurrentLogVersion() {
+ return this.logVersionRepository.getCurrentLogVersion();
+ }
+
+ @Override
+ public long getCheckpointLogVersion() {
+ return this.logVersionRepository.getCheckpointLogVersion();
+ }
+
+ @Override
+ public long nextCommittingTransactionId() {
+ return this.transactionIdStore.nextCommittingTransactionId();
+ }
+
+ @Override
+ public long committingTransactionId() {
+ return this.transactionIdStore.committingTransactionId();
+ }
+
+ @Override
+ public long getLastCommittedTransactionId() {
+ return this.transactionIdStore.getLastCommittedTransactionId();
+ }
+
+ @Override
+ public TransactionId getLastCommittedTransaction() {
+ return this.transactionIdStore.getLastCommittedTransaction();
+ }
+
+ @Override
+ public long getLastClosedTransactionId() {
+ return this.transactionIdStore.getLastClosedTransactionId();
+ }
+
+ @Override
+ public Optional getDatabaseIdUuid(CursorContext cursorTracer) {
+ throw new IllegalStateException("Not supported");
+ }
+
+ @Override
+ public void setDatabaseIdUuid(UUID uuid, CursorContext cursorContext) {
+ throw new IllegalStateException("Not supported");
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodeCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodeCursor.java
new file mode 100644
index 00000000000..3b1e13f7184
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodeCursor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
+import org.neo4j.storageengine.api.AllNodeScan;
+import org.neo4j.storageengine.api.Degrees;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.RelationshipSelection;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryNodeCursor extends AbstractInMemoryNodeCursor {
+
+ public InMemoryNodeCursor(GraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public boolean hasLabel() {
+ return hasAtLeastOneLabelForCurrentNode();
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(StoragePropertyCursor propertyCursor, PropertySelection selection) {
+ propertyCursor.initNodeProperties(propertiesReference(), selection);
+ }
+
+ @Override
+ public void properties(StoragePropertyCursor propertyCursor) {
+ properties(propertyCursor, PropertySelection.ALL_PROPERTIES);
+ }
+
+ @Override
+ public boolean supportsFastRelationshipsTo() {
+ return false;
+ }
+
+ @Override
+ public void relationshipsTo(
+ StorageRelationshipTraversalCursor storageRelationshipTraversalCursor,
+ RelationshipSelection relationshipSelection,
+ long neighbourNodeReference
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void degrees(RelationshipSelection selection, Degrees.Mutator mutator) {
+ }
+
+ @Override
+ public boolean scanBatch(AllNodeScan allNodeScan, long sizeHint) {
+ return super.scanBatch(allNodeScan, (int) sizeHint);
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodePropertyCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodePropertyCursor.java
new file mode 100644
index 00000000000..41133f54533
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryNodePropertyCursor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryNodePropertyCursor extends AbstractInMemoryNodePropertyCursor {
+
+ public InMemoryNodePropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ reset();
+ setId(((LongReference) reference).id);
+ setPropertySelection(new InMemoryPropertySelectionImpl(selection));
+ }
+
+ @Override
+ public void initRelationshipProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertyCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertyCursor.java
new file mode 100644
index 00000000000..2478a7ca9f5
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertyCursor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.AbstractInMemoryPropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StorageNodeCursor;
+import org.neo4j.storageengine.api.StorageRelationshipCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryPropertyCursor extends AbstractInMemoryPropertyCursor {
+
+ public InMemoryPropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryNodePropertyCursor)) {
+ this.delegate = new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryNodePropertyCursor) delegate).initNodeProperties(reference, selection);
+ }
+
+ @Override
+ public void initNodeProperties(StorageNodeCursor nodeCursor, PropertySelection selection) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryNodePropertyCursor)) {
+ this.delegate = new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryNodePropertyCursor) delegate).initNodeProperties(nodeCursor, selection);
+ }
+
+ @Override
+ public void initRelationshipProperties(StorageRelationshipCursor relationshipCursor, PropertySelection selection) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryRelationshipPropertyCursor)) {
+ this.delegate = new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryRelationshipPropertyCursor) delegate).initRelationshipProperties(relationshipCursor, selection);
+ }
+
+ @Override
+ public void initRelationshipProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryRelationshipPropertyCursor)) {
+ this.delegate = new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryRelationshipPropertyCursor) delegate).initRelationshipProperties(reference, selection);
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertySelectionImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertySelectionImpl.java
new file mode 100644
index 00000000000..d48bf99cb54
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryPropertySelectionImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.InMemoryPropertySelection;
+import org.neo4j.storageengine.api.PropertySelection;
+
+public class InMemoryPropertySelectionImpl implements InMemoryPropertySelection {
+
+ private final PropertySelection propertySelection;
+
+ public InMemoryPropertySelectionImpl(PropertySelection propertySelection) {this.propertySelection = propertySelection;}
+
+ @Override
+ public boolean isLimited() {
+ return propertySelection.isLimited();
+ }
+
+ @Override
+ public int numberOfKeys() {
+ return propertySelection.numberOfKeys();
+ }
+
+ @Override
+ public int key(int index) {
+ return propertySelection.key(index);
+ }
+
+ @Override
+ public boolean test(int key) {
+ return propertySelection.test(key);
+ }
+
+ @Override
+ public boolean isKeysOnly() {
+ return propertySelection.isKeysOnly();
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipPropertyCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipPropertyCursor.java
new file mode 100644
index 00000000000..dc4ad73301e
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipPropertyCursor.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipPropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.gds.storageengine.InMemoryRelationshipCursor;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StorageRelationshipCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipPropertyCursor extends AbstractInMemoryRelationshipPropertyCursor {
+
+ InMemoryRelationshipPropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(
+ Reference reference, PropertySelection propertySelection, long ownerReference
+ ) {
+
+ }
+
+ @Override
+ public void initRelationshipProperties(
+ Reference reference, PropertySelection propertySelection, long ownerReference
+ ) {
+ var relationshipId = ((LongReference) reference).id;
+ var relationshipCursor = new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ relationshipCursor.single(relationshipId);
+ relationshipCursor.next();
+ relationshipCursor.properties(this, new InMemoryPropertySelectionImpl(propertySelection));
+ }
+
+ @Override
+ public void initRelationshipProperties(StorageRelationshipCursor relationshipCursor, PropertySelection selection) {
+ var inMemoryRelationshipCursor = (InMemoryRelationshipCursor) relationshipCursor;
+ inMemoryRelationshipCursor.properties(this, selection);
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipScanCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipScanCursor.java
new file mode 100644
index 00000000000..7ab410e6661
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipScanCursor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
+import org.neo4j.storageengine.api.AllRelationshipsScan;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipScanCursor extends AbstractInMemoryRelationshipScanCursor {
+
+ public InMemoryRelationshipScanCursor(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void single(long reference, long sourceNodeReference, int type, long targetNodeReference) {
+ single(reference);
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(
+ StoragePropertyCursor storagePropertyCursor, PropertySelection propertySelection
+ ) {
+ properties(storagePropertyCursor, new InMemoryPropertySelectionImpl(propertySelection));
+ }
+
+ @Override
+ public boolean scanBatch(AllRelationshipsScan allRelationshipsScan, long sizeHint) {
+ return super.scanBatch(allRelationshipsScan, (int) sizeHint);
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipTraversalCursor.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipTraversalCursor.java
new file mode 100644
index 00000000000..19d93b86a4c
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryRelationshipTraversalCursor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipTraversalCursor extends AbstractInMemoryRelationshipTraversalCursor {
+
+ public InMemoryRelationshipTraversalCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(
+ StoragePropertyCursor propertyCursor, PropertySelection selection
+ ) {
+ properties(propertyCursor, new InMemoryPropertySelectionImpl(selection));
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java
new file mode 100644
index 00000000000..e1c2e09a95c
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineFactory.java
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.eclipse.collections.api.factory.Sets;
+import org.eclipse.collections.api.set.ImmutableSet;
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.configuration.Config;
+import org.neo4j.consistency.checking.ConsistencyFlags;
+import org.neo4j.consistency.report.ConsistencySummaryStatistics;
+import org.neo4j.dbms.database.readonly.DatabaseReadOnlyChecker;
+import org.neo4j.function.ThrowingSupplier;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineFactoryIdProvider;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
+import org.neo4j.internal.batchimport.AdditionalInitialIds;
+import org.neo4j.internal.batchimport.BatchImporter;
+import org.neo4j.internal.batchimport.Configuration;
+import org.neo4j.internal.batchimport.IncrementalBatchImporter;
+import org.neo4j.internal.batchimport.IndexImporterFactory;
+import org.neo4j.internal.batchimport.Monitor;
+import org.neo4j.internal.batchimport.ReadBehaviour;
+import org.neo4j.internal.batchimport.input.Collector;
+import org.neo4j.internal.batchimport.input.Input;
+import org.neo4j.internal.batchimport.input.LenientStoreInput;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.id.ScanOnOpenReadOnlyIdGeneratorFactory;
+import org.neo4j.internal.recordstorage.InMemoryStorageCommandReaderFactory510;
+import org.neo4j.internal.recordstorage.StoreTokens;
+import org.neo4j.internal.schema.IndexConfigCompleter;
+import org.neo4j.internal.schema.SchemaRule;
+import org.neo4j.internal.schema.SchemaState;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.layout.recordstorage.RecordDatabaseLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.kernel.KernelVersionRepository;
+import org.neo4j.kernel.api.index.IndexProvidersAccess;
+import org.neo4j.kernel.impl.api.index.IndexProviderMap;
+import org.neo4j.kernel.impl.locking.LockManager;
+import org.neo4j.kernel.impl.store.MetaDataStore;
+import org.neo4j.kernel.impl.store.NeoStores;
+import org.neo4j.kernel.impl.store.StoreFactory;
+import org.neo4j.kernel.impl.store.StoreType;
+import org.neo4j.kernel.impl.store.cursor.CachedStoreCursors;
+import org.neo4j.kernel.impl.transaction.log.LogTailLogVersionsMetadata;
+import org.neo4j.kernel.impl.transaction.log.LogTailMetadata;
+import org.neo4j.lock.LockService;
+import org.neo4j.logging.InternalLog;
+import org.neo4j.logging.InternalLogProvider;
+import org.neo4j.logging.NullLogProvider;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.monitoring.DatabaseHealth;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+import org.neo4j.storageengine.api.ConstraintRuleAccessor;
+import org.neo4j.storageengine.api.LogFilesInitializer;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.SchemaRule44;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageFilesState;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.StoreVersionIdentifier;
+import org.neo4j.storageengine.migration.SchemaRuleMigrationAccessExtended;
+import org.neo4j.storageengine.migration.StoreMigrationParticipant;
+import org.neo4j.time.SystemNanoClock;
+import org.neo4j.token.DelegatingTokenHolder;
+import org.neo4j.token.ReadOnlyTokenCreator;
+import org.neo4j.token.TokenHolders;
+import org.neo4j.token.api.NamedToken;
+import org.neo4j.token.api.TokenHolder;
+import org.neo4j.token.api.TokensLoader;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.time.Clock;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Function;
+
+@ServiceProvider
+public class InMemoryStorageEngineFactory implements StorageEngineFactory {
+
+ static final String IN_MEMORY_STORAGE_ENGINE_NAME = "in-memory-510";
+
+ public InMemoryStorageEngineFactory() {
+ StorageEngineProxyApi.requireNeo4jVersion(Neo4jVersion.V_5_10, StorageEngineFactory.class);
+ }
+
+ @Override
+ public byte id() {
+ return StorageEngineFactoryIdProvider.ID;
+ }
+
+ @Override
+ public boolean storageExists(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout) {
+ return false;
+ }
+
+ @Override
+ public StorageEngine instantiate(
+ FileSystemAbstraction fs,
+ Clock clock,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ TokenHolders tokenHolders,
+ SchemaState schemaState,
+ ConstraintRuleAccessor constraintSemantics,
+ IndexConfigCompleter indexConfigCompleter,
+ LockService lockService,
+ IdGeneratorFactory idGeneratorFactory,
+ DatabaseHealth databaseHealth,
+ InternalLogProvider internalLogProvider,
+ InternalLogProvider userLogProvider,
+ RecoveryCleanupWorkCollector recoveryCleanupWorkCollector,
+ LogTailMetadata logTailMetadata,
+ KernelVersionRepository kernelVersionRepository,
+ MemoryTracker memoryTracker,
+ CursorContextFactory contextFactory,
+ PageCacheTracer pageCacheTracer
+ ) {
+ StoreFactory factory = new StoreFactory(
+ databaseLayout,
+ config,
+ idGeneratorFactory,
+ pageCache,
+ pageCacheTracer,
+ fs,
+ internalLogProvider,
+ contextFactory,
+ false,
+ logTailMetadata
+ );
+
+ factory.openNeoStores(StoreType.LABEL_TOKEN).close();
+
+ return new InMemoryStorageEngineImpl(
+ databaseLayout,
+ tokenHolders
+ );
+ }
+
+ @Override
+ public Optional databaseIdUuid(
+ FileSystemAbstraction fs, DatabaseLayout databaseLayout, PageCache pageCache, CursorContext cursorContext
+ ) {
+ var fieldAccess = MetaDataStore.getFieldAccess(
+ pageCache,
+ RecordDatabaseLayout.convert(databaseLayout).metadataStore(),
+ databaseLayout.getDatabaseName(),
+ cursorContext
+ );
+
+ try {
+ return fieldAccess.readDatabaseUUID();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public List migrationParticipants(
+ FileSystemAbstraction fileSystemAbstraction,
+ Config config,
+ PageCache pageCache,
+ JobScheduler jobScheduler,
+ LogService logService,
+ MemoryTracker memoryTracker,
+ PageCacheTracer pageCacheTracer,
+ CursorContextFactory cursorContextFactory,
+ boolean b
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public DatabaseLayout databaseLayout(
+ Neo4jLayout neo4jLayout, String databaseName
+ ) {
+ return RecordDatabaseLayout.of(neo4jLayout, databaseName);
+ }
+
+ @Override
+ public DatabaseLayout formatSpecificDatabaseLayout(DatabaseLayout plainLayout) {
+ return databaseLayout(plainLayout.getNeo4jLayout(), plainLayout.getDatabaseName());
+ }
+
+ @Override
+ public SchemaRuleMigrationAccessExtended schemaRuleMigrationAccess(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContextFactory contextFactory,
+ MemoryTracker memoryTracker
+ ) throws IOException {
+ return null; // Store copy that uses this method doesn't accept GDS in memory store formats target
+ }
+
+ @SuppressForbidden(reason = "This is the compat layer and we don't really need to go through the proxy")
+ @Override
+ public BatchImporter batchImporter(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ PrintStream printStream,
+ boolean b,
+ AdditionalInitialIds additionalInitialIds,
+ Config config,
+ Monitor monitor,
+ JobScheduler jobScheduler,
+ Collector collector,
+ LogFilesInitializer logFilesInitializer,
+ IndexImporterFactory indexImporterFactory,
+ MemoryTracker memoryTracker,
+ CursorContextFactory cursorContextFactory
+ ) {
+ throw new UnsupportedOperationException("Batch Import into GDS is not supported");
+ }
+
+ @Override
+ public Input asBatchImporterInput(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ MemoryTracker memoryTracker,
+ ReadBehaviour readBehaviour,
+ boolean b,
+ CursorContextFactory cursorContextFactory,
+ LogTailMetadata logTailMetadata
+ ) {
+ NeoStores neoStores = (new StoreFactory(
+ databaseLayout,
+ config,
+ new ScanOnOpenReadOnlyIdGeneratorFactory(),
+ pageCache,
+ pageCacheTracer,
+ fileSystemAbstraction,
+ NullLogProvider.getInstance(),
+ cursorContextFactory,
+ false,
+ logTailMetadata
+ )).openAllNeoStores();
+ return new LenientStoreInput(
+ neoStores,
+ readBehaviour.decorateTokenHolders(this.loadReadOnlyTokens(neoStores, true, cursorContextFactory)),
+ true,
+ cursorContextFactory,
+ readBehaviour
+ );
+ }
+
+ @Override
+ public long optimalAvailableConsistencyCheckerMemory(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache
+ ) {
+ return 0;
+ }
+
+ @Override
+ public String name() {
+ return IN_MEMORY_STORAGE_ENGINE_NAME;
+ }
+
+ @Override
+ public Set supportedFormats(boolean includeFormatsUnderDevelopment) {
+ return Set.of(IN_MEMORY_STORAGE_ENGINE_NAME);
+ }
+
+ @Override
+ public boolean supportedFormat(String format, boolean includeFormatsUnderDevelopment) {
+ return format.equals(IN_MEMORY_STORAGE_ENGINE_NAME);
+ }
+
+ @Override
+ public MetadataProvider transactionMetaDataStore(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ DatabaseReadOnlyChecker readOnlyChecker,
+ CursorContextFactory contextFactory,
+ LogTailLogVersionsMetadata logTailMetadata,
+ PageCacheTracer pageCacheTracer
+ ) {
+ return new InMemoryMetaDataProviderImpl();
+ }
+
+ @Override
+ public StoreVersionCheck versionCheck(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ LogService logService,
+ CursorContextFactory cursorContextFactory
+ ) {
+ return new InMemoryVersionCheck();
+ }
+
+ @Override
+ public List loadSchemaRules(
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ boolean b,
+ Function function,
+ CursorContextFactory cursorContextFactory
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public List load44SchemaRules(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContextFactory contextFactory,
+ LogTailLogVersionsMetadata logTailMetadata
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public TokenHolders loadReadOnlyTokens(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ boolean lenient,
+ CursorContextFactory cursorContextFactory
+ ) {
+ StoreFactory factory = new StoreFactory(
+ databaseLayout,
+ config,
+ new ScanOnOpenReadOnlyIdGeneratorFactory(),
+ pageCache,
+ pageCacheTracer,
+ fileSystemAbstraction,
+ NullLogProvider.getInstance(),
+ cursorContextFactory,
+ false,
+ LogTailMetadata.EMPTY_LOG_TAIL
+ );
+ try ( NeoStores stores = factory.openNeoStores(
+ StoreType.PROPERTY_KEY_TOKEN, StoreType.PROPERTY_KEY_TOKEN_NAME,
+ StoreType.LABEL_TOKEN, StoreType.LABEL_TOKEN_NAME,
+ StoreType.RELATIONSHIP_TYPE_TOKEN, StoreType.RELATIONSHIP_TYPE_TOKEN_NAME ) )
+ {
+ return loadReadOnlyTokens(stores, lenient, cursorContextFactory);
+ }
+ }
+
+ private TokenHolders loadReadOnlyTokens(
+ NeoStores stores,
+ boolean lenient,
+ CursorContextFactory cursorContextFactory
+ )
+ {
+ try ( var cursorContext = cursorContextFactory.create("loadReadOnlyTokens");
+ var storeCursors = new CachedStoreCursors( stores, cursorContext ) )
+ {
+ stores.start( cursorContext );
+ TokensLoader loader = lenient ? StoreTokens.allReadableTokens( stores ) : StoreTokens.allTokens( stores );
+ TokenHolder propertyKeys = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_PROPERTY_KEY );
+ TokenHolder labels = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_LABEL );
+ TokenHolder relationshipTypes = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_RELATIONSHIP_TYPE );
+
+ propertyKeys.setInitialTokens( lenient ? unique( loader.getPropertyKeyTokens( storeCursors ) ) : loader.getPropertyKeyTokens( storeCursors ) );
+ labels.setInitialTokens( lenient ? unique( loader.getLabelTokens( storeCursors ) ) : loader.getLabelTokens( storeCursors ) );
+ relationshipTypes.setInitialTokens(
+ lenient ? unique( loader.getRelationshipTypeTokens( storeCursors ) ) : loader.getRelationshipTypeTokens( storeCursors ) );
+ return new TokenHolders( propertyKeys, labels, relationshipTypes );
+ }
+ catch ( IOException e )
+ {
+ throw new UncheckedIOException( e );
+ }
+ }
+
+ private static List unique( List tokens )
+ {
+ if ( !tokens.isEmpty() )
+ {
+ Set names = new HashSet<>( tokens.size() );
+ int i = 0;
+ while ( i < tokens.size() )
+ {
+ if ( names.add( tokens.get( i ).name() ) )
+ {
+ i++;
+ }
+ else
+ {
+ // Remove the token at the given index, by replacing it with the last token in the list.
+ // This changes the order of elements, but can be done in constant time instead of linear time.
+ int lastIndex = tokens.size() - 1;
+ NamedToken endToken = tokens.remove( lastIndex );
+ if ( i < lastIndex )
+ {
+ tokens.set( i, endToken );
+ }
+ }
+ }
+ }
+ return tokens;
+ }
+
+ @Override
+ public CommandReaderFactory commandReaderFactory() {
+ return InMemoryStorageCommandReaderFactory510.INSTANCE;
+ }
+
+ @Override
+ public void consistencyCheck(
+ FileSystemAbstraction fileSystem,
+ DatabaseLayout layout,
+ Config config,
+ PageCache pageCache,
+ IndexProviderMap indexProviders,
+ InternalLog log,
+ ConsistencySummaryStatistics summary,
+ int numberOfThreads,
+ long maxOffHeapCachingMemory,
+ OutputStream progressOutput,
+ boolean verbose,
+ ConsistencyFlags flags,
+ CursorContextFactory contextFactory,
+ PageCacheTracer pageCacheTracer,
+ LogTailMetadata logTailMetadata
+ ) {
+ // we can do no-op, since our "database" is _always_ consistent
+ }
+
+ @Override
+ public ImmutableSet getStoreOpenOptions(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ DatabaseLayout layout,
+ CursorContextFactory contextFactory
+ ) {
+ // Not sure about this, empty set is returned when the store files are in `little-endian` format
+ // See: `org.neo4j.kernel.impl.store.format.PageCacheOptionsSelector.select`
+ return Sets.immutable.empty();
+ }
+
+ @Override
+ public StoreId retrieveStoreId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ return StoreId.retrieveFromStore(fs, databaseLayout, pageCache, cursorContext);
+ }
+
+
+ @Override
+ public Optional versionInformation(StoreVersionIdentifier storeVersionIdentifier) {
+ return Optional.of(new InMemoryStoreVersion());
+ }
+
+ @Override
+ public void resetMetadata(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ CursorContextFactory cursorContextFactory,
+ PageCacheTracer pageCacheTracer,
+ StoreId storeId,
+ UUID externalStoreId
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IncrementalBatchImporter incrementalBatchImporter(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystem,
+ PageCacheTracer pageCacheTracer,
+ Configuration config,
+ LogService logService,
+ PrintStream progressOutput,
+ boolean verboseProgressOutput,
+ AdditionalInitialIds additionalInitialIds,
+ ThrowingSupplier logTailMetadataSupplier,
+ Config dbConfig,
+ Monitor monitor,
+ JobScheduler jobScheduler,
+ Collector badCollector,
+ LogFilesInitializer logFilesInitializer,
+ IndexImporterFactory indexImporterFactory,
+ MemoryTracker memoryTracker,
+ CursorContextFactory contextFactory,
+ IndexProvidersAccess indexProvidersAccess
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public LockManager createLockManager(Config config, SystemNanoClock clock) {
+ return LockManager.NO_LOCKS_LOCK_MANAGER;
+ }
+
+ @Override
+ public List listStorageFiles(
+ FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public StorageFilesState checkStoreFileState(
+ FileSystemAbstraction fs, DatabaseLayout databaseLayout, PageCache pageCache
+ ) {
+ return StorageFilesState.recoveredState();
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineImpl.java
new file mode 100644
index 00000000000..484f0c1a19a
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageEngineImpl.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.counts.CountsAccessor;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.gds.compat.TokenManager;
+import org.neo4j.gds.config.GraphProjectConfig;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.gds.core.loading.GraphStoreCatalog;
+import org.neo4j.gds.storageengine.InMemoryDatabaseCreationCatalog;
+import org.neo4j.gds.storageengine.InMemoryTransactionStateVisitor;
+import org.neo4j.internal.diagnostics.DiagnosticsLogger;
+import org.neo4j.internal.recordstorage.InMemoryStorageReader510;
+import org.neo4j.internal.schema.StorageEngineIndexingBehaviour;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.tracing.DatabaseFlushEvent;
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.kernel.impl.store.stats.StoreEntityCounters;
+import org.neo4j.kernel.lifecycle.Lifecycle;
+import org.neo4j.kernel.lifecycle.LifecycleAdapter;
+import org.neo4j.lock.LockGroup;
+import org.neo4j.lock.LockService;
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.logging.InternalLog;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.storageengine.api.CommandBatchToApply;
+import org.neo4j.storageengine.api.CommandCreationContext;
+import org.neo4j.storageengine.api.CommandStream;
+import org.neo4j.storageengine.api.IndexUpdateListener;
+import org.neo4j.storageengine.api.InternalErrorTracer;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StorageCommand;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageLocks;
+import org.neo4j.storageengine.api.StorageReader;
+import org.neo4j.storageengine.api.StoreFileMetadata;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.TransactionApplicationMode;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+import org.neo4j.storageengine.api.enrichment.Enrichment;
+import org.neo4j.storageengine.api.enrichment.EnrichmentCommand;
+import org.neo4j.storageengine.api.txstate.ReadableTransactionState;
+import org.neo4j.storageengine.api.txstate.TxStateVisitor;
+import org.neo4j.storageengine.api.txstate.validation.TransactionValidatorFactory;
+import org.neo4j.time.SystemNanoClock;
+import org.neo4j.token.TokenHolders;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
+
+public final class InMemoryStorageEngineImpl implements StorageEngine {
+
+ public static final byte ID = 42;
+ private final MetadataProvider metadataProvider;
+ private final CypherGraphStore graphStore;
+ private final DatabaseLayout databaseLayout;
+ private final InMemoryTransactionStateVisitor txStateVisitor;
+
+ private final CommandCreationContext commandCreationContext;
+
+ private final TokenManager tokenManager;
+ private final InMemoryCountsStoreImpl countsStore;
+
+ private static final StorageEngineIndexingBehaviour INDEXING_BEHAVIOUR = new StorageEngineIndexingBehaviour() {
+ @Override
+ public boolean useNodeIdsInRelationshipTokenIndex() {
+ return false;
+ }
+
+ @Override
+ public boolean requireCoordinationLocks() {
+ return false;
+ }
+
+ @Override
+ public int nodesPerPage() {
+ return 0;
+ }
+
+ @Override
+ public int relationshipsPerPage() {
+ return 0;
+ }
+ };
+
+ InMemoryStorageEngineImpl(
+ DatabaseLayout databaseLayout,
+ TokenHolders tokenHolders
+ ) {
+ this.databaseLayout = databaseLayout;
+ this.graphStore = getGraphStoreFromCatalog(databaseLayout.getDatabaseName());
+ this.txStateVisitor = new InMemoryTransactionStateVisitor(graphStore, tokenHolders);
+ this.commandCreationContext = new InMemoryCommandCreationContextImpl();
+ this.tokenManager = new TokenManager(
+ tokenHolders,
+ InMemoryStorageEngineImpl.this.txStateVisitor,
+ InMemoryStorageEngineImpl.this.graphStore,
+ commandCreationContext
+ );
+ InMemoryStorageEngineImpl.this.graphStore.initialize(tokenHolders);
+ this.countsStore = new InMemoryCountsStoreImpl(graphStore, tokenHolders);
+ this.metadataProvider = new InMemoryMetaDataProviderImpl();
+ }
+
+ private static CypherGraphStore getGraphStoreFromCatalog(String databaseName) {
+ var graphName = InMemoryDatabaseCreationCatalog.getRegisteredDbCreationGraphName(databaseName);
+ return (CypherGraphStore) GraphStoreCatalog.getAllGraphStores()
+ .filter(graphStoreWithUserNameAndConfig -> graphStoreWithUserNameAndConfig
+ .config()
+ .graphName()
+ .equals(graphName))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(formatWithLocale(
+ "No graph with name `%s` was found in GraphStoreCatalog. Available graph names are %s",
+ graphName,
+ GraphStoreCatalog.getAllGraphStores()
+ .map(GraphStoreCatalog.GraphStoreWithUserNameAndConfig::config)
+ .map(GraphProjectConfig::graphName)
+ .collect(Collectors.toList())
+ )))
+ .graphStore();
+ }
+
+ @Override
+ public StoreEntityCounters storeEntityCounters() {
+ return new StoreEntityCounters() {
+ @Override
+ public long nodes() {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public long relationships() {
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public long properties() {
+ return graphStore.nodePropertyKeys().size() + graphStore.relationshipPropertyKeys().size();
+ }
+
+ @Override
+ public long relationshipTypes() {
+ return graphStore.relationshipTypes().size();
+ }
+
+ @Override
+ public long allNodesCountStore(CursorContext cursorContext) {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public long allRelationshipsCountStore(CursorContext cursorContext) {
+ return graphStore.relationshipCount();
+ }
+ };
+ }
+
+ @Override
+ public void preAllocateStoreFilesForCommands(
+ CommandBatchToApply commandBatchToApply,
+ TransactionApplicationMode transactionApplicationMode
+ ) {
+ }
+
+ @Override
+ public StoreCursors createStorageCursors(CursorContext initialContext) {
+ return StoreCursors.NULL;
+ }
+
+ @Override
+ public StorageLocks createStorageLocks(ResourceLocker locker) {
+ return new InMemoryStorageLocksImpl(locker);
+ }
+
+ @Override
+ public List createCommands(
+ ReadableTransactionState state,
+ StorageReader storageReader,
+ CommandCreationContext creationContext,
+ LockTracer lockTracer,
+ TxStateVisitor.Decorator additionalTxStateVisitor,
+ CursorContext cursorContext,
+ StoreCursors storeCursors,
+ MemoryTracker memoryTracker
+ ) throws KernelException {
+ state.accept(txStateVisitor);
+ return List.of();
+ }
+
+ @Override
+ public void dumpDiagnostics(InternalLog internalLog, DiagnosticsLogger diagnosticsLogger) {
+ }
+
+ @Override
+ public List createUpgradeCommands(
+ KernelVersion versionToUpgradeFrom,
+ KernelVersion versionToUpgradeTo
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public EnrichmentCommand createEnrichmentCommand(KernelVersion kernelVersion, Enrichment enrichment) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public StoreId retrieveStoreId() {
+ return metadataProvider.getStoreId();
+ }
+
+ @Override
+ public StorageEngineIndexingBehaviour indexingBehaviour() {
+ return INDEXING_BEHAVIOUR;
+ }
+
+ @Override
+ public StorageReader newReader() {
+ return new InMemoryStorageReader510(graphStore, tokenManager.tokenHolders(), countsStore);
+ }
+
+ @Override
+ public void addIndexUpdateListener(IndexUpdateListener listener) {
+
+ }
+
+ @Override
+ public void apply(CommandBatchToApply batch, TransactionApplicationMode mode) {
+ }
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void stop() {
+ shutdown();
+ }
+
+ @Override
+ public void shutdown() {
+ InMemoryDatabaseCreationCatalog.removeDatabaseEntry(databaseLayout.getDatabaseName());
+ }
+
+ @Override
+ public void listStorageFiles(
+ Collection atomic, Collection replayable
+ ) {
+
+ }
+
+ @Override
+ public Lifecycle schemaAndTokensLifecycle() {
+ return new LifecycleAdapter() {
+ @Override
+ public void init() {
+
+ }
+ };
+ }
+
+ @Override
+ public CountsAccessor countsAccessor() {
+ return countsStore;
+ }
+
+ @Override
+ public MetadataProvider metadataProvider() {
+ return metadataProvider;
+ }
+
+ @Override
+ public String name() {
+ return "gds in-memory storage engine";
+ }
+
+ @Override
+ public byte id() {
+ return ID;
+ }
+
+ @Override
+ public CommandCreationContext newCommandCreationContext() {
+ return commandCreationContext;
+ }
+
+ @Override
+ public TransactionValidatorFactory createTransactionValidatorFactory(StorageEngineFactory storageEngineFactory, Config config, SystemNanoClock clock) {
+ return TransactionValidatorFactory.EMPTY_VALIDATOR_FACTORY;
+ }
+
+ @Override
+ public void lockRecoveryCommands(
+ CommandStream commands, LockService lockService, LockGroup lockGroup, TransactionApplicationMode mode
+ ) {
+
+ }
+
+ @Override
+ public void rollback(ReadableTransactionState txState, CursorContext cursorContext) {
+ // rollback is not supported but it is also called when we fail for something else
+ // that we do not support, such as removing node properties
+ // TODO: do we want to inspect the txState to infer if rollback was called explicitly or not?
+ }
+
+ @Override
+ public void checkpoint(DatabaseFlushEvent flushEvent, CursorContext cursorContext) {
+ // checkpoint is not supported but it is also called when we fail for something else
+ // that we do not support, such as removing node properties
+ }
+
+ @Override
+ public InternalErrorTracer internalErrorTracer() {
+ return InternalErrorTracer.NO_TRACER;
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageLocksImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageLocksImpl.java
new file mode 100644
index 00000000000..bbc08d7e808
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStorageLocksImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.storageengine.api.StorageLocks;
+import org.neo4j.storageengine.api.txstate.ReadableTransactionState;
+
+public class InMemoryStorageLocksImpl implements StorageLocks {
+
+ InMemoryStorageLocksImpl(ResourceLocker locker) {}
+
+ @Override
+ public void acquireExclusiveNodeLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseExclusiveNodeLock(long... ids) {}
+
+ @Override
+ public void acquireSharedNodeLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseSharedNodeLock(long... ids) {}
+
+ @Override
+ public void acquireExclusiveRelationshipLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseExclusiveRelationshipLock(long... ids) {}
+
+ @Override
+ public void acquireSharedRelationshipLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseSharedRelationshipLock(long... ids) {}
+
+ @Override
+ public void acquireRelationshipCreationLock(
+ LockTracer lockTracer,
+ long sourceNode,
+ long targetNode,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ }
+
+ @Override
+ public void acquireRelationshipDeletionLock(
+ LockTracer lockTracer,
+ long sourceNode,
+ long targetNode,
+ long relationship,
+ boolean relationshipAddedInTx,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ }
+
+ @Override
+ public void acquireNodeDeletionLock(
+ ReadableTransactionState readableTransactionState,
+ LockTracer lockTracer,
+ long node
+ ) {}
+
+ @Override
+ public void acquireNodeLabelChangeLock(LockTracer lockTracer, long node, int labelId) {}
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStoreVersion.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStoreVersion.java
new file mode 100644
index 00000000000..669b0bf4983
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryStoreVersion.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.format.Capability;
+import org.neo4j.storageengine.api.format.CapabilityType;
+
+import java.util.Optional;
+
+public class InMemoryStoreVersion implements StoreVersion {
+
+ public static final String STORE_VERSION = "gds-experimental";
+
+ @Override
+ public String getStoreVersionUserString() {
+ return "Unknown";
+ }
+
+ @Override
+ public Optional successorStoreVersion(Config config) {
+ return Optional.empty();
+ }
+
+ @Override
+ public String formatName() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean onlyForMigration() {
+ return false;
+ }
+
+ @Override
+ public boolean hasCapability(Capability capability) {
+ return false;
+ }
+
+ @Override
+ public boolean hasCompatibleCapabilities(
+ StoreVersion otherVersion, CapabilityType type
+ ) {
+ return false;
+ }
+
+ @Override
+ public String introductionNeo4jVersion() {
+ return "foo";
+ }
+
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryTransactionIdStoreImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryTransactionIdStoreImpl.java
new file mode 100644
index 00000000000..2a7a57be260
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryTransactionIdStoreImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.internal.recordstorage.AbstractTransactionIdStore;
+import org.neo4j.io.pagecache.context.TransactionIdSnapshot;
+import org.neo4j.kernel.impl.transaction.log.LogPosition;
+import org.neo4j.storageengine.api.ClosedTransactionMetadata;
+import org.neo4j.storageengine.api.TransactionId;
+import org.neo4j.storageengine.api.TransactionIdStore;
+
+public class InMemoryTransactionIdStoreImpl extends AbstractTransactionIdStore {
+
+ @Override
+ protected void initLastCommittedAndClosedTransactionId(
+ long previouslyCommittedTxId,
+ int checksum,
+ long previouslyCommittedTxCommitTimestamp,
+ long previouslyCommittedTxLogByteOffset,
+ long previouslyCommittedTxLogVersion
+ ) {
+ this.setLastCommittedAndClosedTransactionId(
+ previouslyCommittedTxId,
+ checksum,
+ previouslyCommittedTxCommitTimestamp,
+ TransactionIdStore.UNKNOWN_CONSENSUS_INDEX,
+ previouslyCommittedTxLogByteOffset,
+ previouslyCommittedTxLogVersion
+ );
+ }
+
+ @Override
+ public ClosedTransactionMetadata getLastClosedTransaction() {
+ long[] metaData = this.closedTransactionId.get();
+ return new ClosedTransactionMetadata(
+ metaData[0],
+ new LogPosition(metaData[1], metaData[2]),
+ (int) metaData[3],
+ metaData[4],
+ metaData[5]
+ );
+ }
+
+ @Override
+ public TransactionIdSnapshot getClosedTransactionSnapshot() {
+ return new TransactionIdSnapshot(this.getLastClosedTransactionId());
+ }
+
+ @Override
+ protected TransactionId transactionId(long transactionId, int checksum, long commitTimestamp) {
+ return new TransactionId(transactionId, checksum, commitTimestamp, TransactionIdStore.UNKNOWN_CONSENSUS_INDEX);
+ }
+
+ @Override
+ public void transactionCommitted(long transactionId, int checksum, long commitTimestamp, long consensusIndex) {
+
+ }
+
+ @Override
+ public void setLastCommittedAndClosedTransactionId(
+ long transactionId,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex,
+ long byteOffset,
+ long logVersion
+ ) {
+
+ }
+
+ @Override
+ public void transactionClosed(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.closedTransactionId.offer(
+ transactionId,
+ new long[]{logVersion, byteOffset, checksum, commitTimestamp, consensusIndex}
+ );
+ }
+
+ @Override
+ public void resetLastClosedTransaction(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.closedTransactionId.set(
+ transactionId,
+ new long[]{logVersion, byteOffset, checksum, commitTimestamp, consensusIndex}
+ );
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryVersionCheck.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryVersionCheck.java
new file mode 100644
index 00000000000..8f32317048b
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/InMemoryVersionCheck.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.kernel.impl.store.format.FormatFamily;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.StoreVersionIdentifier;
+
+import static org.neo4j.gds.compat._510.InMemoryStoreVersion.STORE_VERSION;
+
+public class InMemoryVersionCheck implements StoreVersionCheck {
+
+ private static final StoreVersionIdentifier STORE_IDENTIFIER = new StoreVersionIdentifier(
+ STORE_VERSION,
+ FormatFamily.STANDARD.name(),
+ 0,
+ 0
+ );
+
+ @Override
+ public boolean isCurrentStoreVersionFullySupported(CursorContext cursorContext) {
+ return true;
+ }
+
+ @Override
+ public MigrationCheckResult getAndCheckMigrationTargetVersion(String formatFamily, CursorContext cursorContext) {
+ return new StoreVersionCheck.MigrationCheckResult(MigrationOutcome.NO_OP, STORE_IDENTIFIER, null, null);
+ }
+
+ @Override
+ public UpgradeCheckResult getAndCheckUpgradeTargetVersion(CursorContext cursorContext) {
+ return new StoreVersionCheck.UpgradeCheckResult(UpgradeOutcome.NO_OP, STORE_IDENTIFIER, null, null);
+ }
+
+ @Override
+ public String getIntroductionVersionFromVersion(StoreVersionIdentifier storeVersionIdentifier) {
+ return STORE_VERSION;
+ }
+
+ public StoreVersionIdentifier findLatestVersion(String s) {
+ return STORE_IDENTIFIER;
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 00000000000..9f5c42c0f5d
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.compat.StorageEngineProxyFactory;
+
+@ServiceProvider
+public class StorageEngineProxyFactoryImpl implements StorageEngineProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_10;
+ }
+
+ @Override
+ public StorageEngineProxyApi load() {
+ return new StorageEngineProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.10";
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyImpl.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyImpl.java
new file mode 100644
index 00000000000..0e4e3e89cf4
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_510/StorageEngineProxyImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._510;
+
+import org.neo4j.common.Edition;
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.GraphDatabaseInternalSettings;
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
+import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipPropertyCursor;
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.RelationshipSelection;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEntityCursor;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.token.TokenHolders;
+
+import static org.neo4j.configuration.GraphDatabaseSettings.db_format;
+
+public class StorageEngineProxyImpl implements StorageEngineProxyApi {
+
+ @Override
+ public void initRelationshipTraversalCursorForRelType(
+ StorageRelationshipTraversalCursor cursor,
+ long sourceNodeId,
+ int relTypeToken
+ ) {
+ var relationshipSelection = RelationshipSelection.selection(
+ relTypeToken,
+ Direction.OUTGOING
+ );
+ cursor.init(sourceNodeId, -1, relationshipSelection);
+ }
+
+ @Override
+ public StorageEngine createInMemoryStorageEngine(DatabaseLayout databaseLayout, TokenHolders tokenHolders) {
+ return new InMemoryStorageEngineImpl(databaseLayout, tokenHolders);
+ }
+
+ @Override
+ public void createInMemoryDatabase(
+ DatabaseManagementService dbms,
+ String dbName,
+ Config config
+ ) {
+ config.set(db_format, InMemoryStorageEngineFactory.IN_MEMORY_STORAGE_ENGINE_NAME);
+ dbms.createDatabase(dbName, config);
+ }
+
+ @Override
+ public GraphDatabaseService startAndGetInMemoryDatabase(DatabaseManagementService dbms, String dbName) {
+ dbms.startDatabase(dbName);
+ return dbms.database(dbName);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setSkipDefaultIndexesOnCreationSetting(GdsDatabaseManagementServiceBuilder dbmsBuilder) {
+ return dbmsBuilder.setConfig(GraphDatabaseInternalSettings.skip_default_indexes_on_creation, true);
+ }
+
+ @Override
+ public AbstractInMemoryNodeCursor inMemoryNodeCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ return new InMemoryNodeCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryNodePropertyCursor inMemoryNodePropertyCursor(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+ return new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipTraversalCursor inMemoryRelationshipTraversalCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipTraversalCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipScanCursor inMemoryRelationshipScanCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipPropertyCursor inMemoryRelationshipPropertyCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void properties(
+ StorageEntityCursor storageCursor, StoragePropertyCursor propertyCursor, int[] propertySelection
+ ) {
+ PropertySelection selection;
+ if (propertySelection.length == 0) {
+ selection = PropertySelection.ALL_PROPERTIES;
+ } else {
+ selection = PropertySelection.selection(propertySelection);
+ }
+ storageCursor.properties(propertyCursor, selection);
+ }
+
+ @Override
+ public Edition dbmsEdition(GraphDatabaseService databaseService) {
+ return GraphDatabaseApiProxy.dbmsInfo(databaseService).edition;
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository510.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository510.java
new file mode 100644
index 00000000000..35b0e6c8dba
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository510.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.neo4j.storageengine.api.LogVersionRepository;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class InMemoryLogVersionRepository510 implements LogVersionRepository {
+
+ private final AtomicLong logVersion;
+ private final AtomicLong checkpointLogVersion;
+
+ public InMemoryLogVersionRepository510() {
+ this(0, 0);
+ }
+
+ private InMemoryLogVersionRepository510(long initialLogVersion, long initialCheckpointLogVersion) {
+ this.logVersion = new AtomicLong();
+ this.checkpointLogVersion = new AtomicLong();
+ this.logVersion.set(initialLogVersion);
+ this.checkpointLogVersion.set(initialCheckpointLogVersion);
+ }
+
+ @Override
+ public void setCurrentLogVersion(long version) {
+ this.logVersion.set(version);
+ }
+
+ @Override
+ public long incrementAndGetVersion() {
+ return this.logVersion.incrementAndGet();
+ }
+
+ @Override
+ public void setCheckpointLogVersion(long version) {
+ this.checkpointLogVersion.set(version);
+ }
+
+ @Override
+ public long incrementAndGetCheckpointLogVersion() {
+ return this.checkpointLogVersion.incrementAndGet();
+ }
+
+ @Override
+ public long getCurrentLogVersion() {
+ return this.logVersion.get();
+ }
+
+ @Override
+ public long getCheckpointLogVersion() {
+ return this.checkpointLogVersion.get();
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory510.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory510.java
new file mode 100644
index 00000000000..710f94121eb
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory510.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.storageengine.api.CommandReader;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+
+public class InMemoryStorageCommandReaderFactory510 implements CommandReaderFactory {
+
+ public static final CommandReaderFactory INSTANCE = new InMemoryStorageCommandReaderFactory510();
+
+ @Override
+ public CommandReader get(KernelVersion kernelVersion) {
+ switch (kernelVersion) {
+ case V4_2:
+ return LogCommandSerializationV4_2.INSTANCE;
+ case V4_3_D4:
+ return LogCommandSerializationV4_3_D3.INSTANCE;
+ case V5_0:
+ return LogCommandSerializationV5_0.INSTANCE;
+ default:
+ throw new IllegalArgumentException("Unsupported kernel version " + kernelVersion);
+ }
+ }
+}
diff --git a/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader510.java b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader510.java
new file mode 100644
index 00000000000..7f5095a1520
--- /dev/null
+++ b/compatibility/5.10/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader510.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.eclipse.collections.api.set.primitive.IntSet;
+import org.eclipse.collections.impl.set.immutable.primitive.ImmutableIntSetFactoryImpl;
+import org.neo4j.common.EntityType;
+import org.neo4j.common.TokenNameLookup;
+import org.neo4j.counts.CountsAccessor;
+import org.neo4j.gds.compat._510.InMemoryNodeCursor;
+import org.neo4j.gds.compat._510.InMemoryPropertyCursor;
+import org.neo4j.gds.compat._510.InMemoryRelationshipScanCursor;
+import org.neo4j.gds.compat._510.InMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.internal.schema.ConstraintDescriptor;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexType;
+import org.neo4j.internal.schema.SchemaDescriptor;
+import org.neo4j.internal.schema.constraints.IndexBackedConstraintDescriptor;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.storageengine.api.AllNodeScan;
+import org.neo4j.storageengine.api.AllRelationshipsScan;
+import org.neo4j.storageengine.api.StorageNodeCursor;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageReader;
+import org.neo4j.storageengine.api.StorageRelationshipScanCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.storageengine.api.StorageSchemaReader;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+import org.neo4j.token.TokenHolders;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+public class InMemoryStorageReader510 implements StorageReader {
+
+ protected final CypherGraphStore graphStore;
+ protected final TokenHolders tokenHolders;
+ protected final CountsAccessor counts;
+ private final Map, Object> dependantState;
+ private boolean closed;
+
+ public InMemoryStorageReader510(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders,
+ CountsAccessor counts
+ ) {
+ this.graphStore = graphStore;
+
+ this.tokenHolders = tokenHolders;
+ this.counts = counts;
+ this.dependantState = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] changedLabels,
+ long[] unchangedLabels,
+ int[] propertyKeyIds,
+ boolean propertyKeyListIsComplete,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public long relationshipsGetCount(CursorContext cursorTracer) {
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public boolean nodeExists(long id, StoreCursors storeCursors) {
+ var originalId = graphStore.nodes().toOriginalNodeId(id);
+ return graphStore.nodes().containsOriginalId(originalId);
+ }
+
+ @Override
+ public boolean relationshipExists(long id, StoreCursors storeCursors) {
+ return true;
+ }
+
+ @Override
+ public StorageNodeCursor allocateNodeCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryNodeCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StoragePropertyCursor allocatePropertyCursor(
+ CursorContext cursorContext, StoreCursors storeCursors, MemoryTracker memoryTracker
+ ) {
+ return new InMemoryPropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StorageRelationshipTraversalCursor allocateRelationshipTraversalCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryRelationshipTraversalCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StorageRelationshipScanCursor allocateRelationshipScanCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public IndexDescriptor indexGetForSchemaAndType(
+ SchemaDescriptor descriptor, IndexType type
+ ) {
+ return null;
+ }
+
+ @Override
+ public AllRelationshipsScan allRelationshipScan() {
+ return new AbstractInMemoryAllRelationshipScan() {
+ @Override
+ boolean scanRange(AbstractInMemoryRelationshipScanCursor cursor, long start, long stopInclusive) {
+ return cursor.scanRange(start, stopInclusive);
+ }
+
+ @Override
+ public boolean scanBatch(long sizeHint, AbstractInMemoryRelationshipScanCursor cursor) {
+ return super.scanBatch(sizeHint, cursor);
+ }
+ };
+ }
+
+ @Override
+ public Iterator indexGetForSchema(SchemaDescriptor descriptor) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator indexesGetForLabel(int labelId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator indexesGetForRelationshipType(int relationshipType) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public IndexDescriptor indexGetForName(String name) {
+ return null;
+ }
+
+ @Override
+ public ConstraintDescriptor constraintGetForName(String name) {
+ return null;
+ }
+
+ @Override
+ public boolean indexExists(IndexDescriptor index) {
+ return false;
+ }
+
+ @Override
+ public Iterator indexesGetAll() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Collection valueIndexesGetRelated(
+ long[] tokens, int propertyKeyId, EntityType entityType
+ ) {
+ return valueIndexesGetRelated(tokens, new int[]{propertyKeyId}, entityType);
+ }
+
+ @Override
+ public Collection valueIndexesGetRelated(
+ long[] tokens, int[] propertyKeyIds, EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] labels,
+ int propertyKeyId,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] tokens,
+ int[] propertyKeyIds,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean hasRelatedSchema(long[] labels, int propertyKey, EntityType entityType) {
+ return false;
+ }
+
+ @Override
+ public boolean hasRelatedSchema(int label, EntityType entityType) {
+ return false;
+ }
+
+ @Override
+ public Iterator constraintsGetForSchema(SchemaDescriptor descriptor) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public boolean constraintExists(ConstraintDescriptor descriptor) {
+ return false;
+ }
+
+ @Override
+ public Iterator constraintsGetForLabel(int labelId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator constraintsGetForRelationshipType(int typeId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator constraintsGetAll() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public IntSet constraintsGetPropertyTokensForLogicalKey(int token, EntityType entityType) {
+ return ImmutableIntSetFactoryImpl.INSTANCE.empty();
+ }
+
+ @Override
+ public Long indexGetOwningUniquenessConstraintId(IndexDescriptor index) {
+ return null;
+ }
+
+ @Override
+ public long countsForNode(int labelId, CursorContext cursorContext) {
+ return counts.nodeCount(labelId, cursorContext);
+ }
+
+ @Override
+ public long countsForRelationship(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ return counts.relationshipCount(startLabelId, typeId, endLabelId, cursorContext);
+ }
+
+ @Override
+ public long nodesGetCount(CursorContext cursorContext) {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public int labelCount() {
+ return graphStore.nodes().availableNodeLabels().size();
+ }
+
+ @Override
+ public int propertyKeyCount() {
+ int nodePropertyCount = graphStore
+ .schema()
+ .nodeSchema()
+ .allProperties()
+ .size();
+ int relPropertyCount = graphStore
+ .schema()
+ .relationshipSchema()
+ .allProperties()
+ .size();
+ return nodePropertyCount + relPropertyCount;
+ }
+
+ @Override
+ public int relationshipTypeCount() {
+ return graphStore.schema().relationshipSchema().availableTypes().size();
+ }
+
+ @Override
+ public T getOrCreateSchemaDependantState(Class type, Function factory) {
+ return type.cast(dependantState.computeIfAbsent(type, key -> factory.apply(this)));
+ }
+
+ @Override
+ public AllNodeScan allNodeScan() {
+ return new InMemoryNodeScan();
+ }
+
+ @Override
+ public void close() {
+ assert !closed;
+ closed = true;
+ }
+
+ @Override
+ public StorageSchemaReader schemaSnapshot() {
+ return this;
+ }
+
+ @Override
+ public TokenNameLookup tokenNameLookup() {
+ return tokenHolders;
+ }
+
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/build.gradle b/compatibility/5.11/neo4j-kernel-adapter/build.gradle
new file mode 100644
index 00000000000..927eee8f07c
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Neo4j Kernel Adapter 5.11'
+
+group = 'org.neo4j.gds'
+
+// for all 5.x versions
+if (ver.'neo4j'.startsWith('5.')) {
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java17']
+ }
+ }
+ }
+
+ dependencies {
+ annotationProcessor project(':annotations')
+ annotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.11'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+ compileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ compileOnly group: 'org.neo4j', name: 'annotations', version: neos.'5.11'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.11'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.11'
+ compileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.11'
+
+ implementation project(':neo4j-kernel-adapter-api')
+ }
+} else {
+ multiRelease {
+ targetVersions 11, 17
+ }
+
+ if (!project.hasProperty('no-forbidden-apis')) {
+ forbiddenApisJava17 {
+ exclude('**')
+ }
+ }
+
+ dependencies {
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ implementation project(':neo4j-kernel-adapter-api')
+
+ java17AnnotationProcessor project(':annotations')
+ java17AnnotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ java17AnnotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.11'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.11'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.11'
+ java17CompileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.11'
+ java17CompileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+
+ java17Implementation project(':neo4j-kernel-adapter-api')
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..32ae5e87d89
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ throw new UnsupportedOperationException("5.11 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.11 (placeholder)";
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..2e0c1a9e2b7
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ throw new UnsupportedOperationException("5.11 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.11 (placeholder)";
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/BoltTransactionRunnerImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/BoltTransactionRunnerImpl.java
new file mode 100644
index 00000000000..f76c6382881
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/BoltTransactionRunnerImpl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.bolt.dbapi.BoltGraphDatabaseServiceSPI;
+import org.neo4j.bolt.dbapi.BoltTransaction;
+import org.neo4j.bolt.protocol.common.message.AccessMode;
+import org.neo4j.bolt.protocol.common.message.request.connection.RoutingContext;
+import org.neo4j.bolt.tx.statement.StatementQuerySubscriber;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.gds.compat.BoltQuerySubscriber;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.graphdb.QueryStatistics;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.QueryExecutionKernelException;
+import org.neo4j.values.virtual.MapValue;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+public class BoltTransactionRunnerImpl extends BoltTransactionRunner {
+
+ @Override
+ protected BoltQuerySubscriber boltQuerySubscriber() {
+ var subscriber = new StatementQuerySubscriber();
+ return new BoltQuerySubscriber<>() {
+ @Override
+ public void assertSucceeded() throws KernelException {
+ subscriber.assertSuccess();
+ }
+
+ @Override
+ public QueryStatistics queryStatistics() {
+ return subscriber.getStatistics();
+ }
+
+ @Override
+ public StatementQuerySubscriber innerSubscriber() {
+ return subscriber;
+ }
+ };
+ }
+
+ @Override
+ protected void executeQuery(
+ BoltTransaction boltTransaction,
+ String query,
+ MapValue parameters,
+ StatementQuerySubscriber querySubscriber
+ ) throws QueryExecutionKernelException {
+ boltTransaction.executeQuery(query, parameters, true, querySubscriber);
+ }
+
+ @Override
+ protected BoltTransaction beginBoltWriteTransaction(
+ BoltGraphDatabaseServiceSPI fabricDb,
+ LoginContext loginContext,
+ KernelTransaction.Type kernelTransactionType,
+ ClientConnectionInfo clientConnectionInfo,
+ List bookmarks,
+ Duration txTimeout,
+ Map txMetadata
+ ) {
+ return fabricDb.beginTransaction(
+ kernelTransactionType,
+ loginContext,
+ clientConnectionInfo,
+ bookmarks,
+ txTimeout,
+ AccessMode.WRITE,
+ txMetadata,
+ new RoutingContext(true, Map.of()),
+ QueryExecutionConfiguration.DEFAULT_CONFIG
+ );
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableProcedureImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableProcedureImpl.java
new file mode 100644
index 00000000000..ac60ee006bd
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableProcedureImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.collection.RawIterator;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.kernel.api.ResourceMonitor;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableProcedureImpl implements CallableProcedure {
+ private final CompatCallableProcedure procedure;
+
+ CallableProcedureImpl(CompatCallableProcedure procedure) {
+ this.procedure = procedure;
+ }
+
+ @Override
+ public ProcedureSignature signature() {
+ return this.procedure.signature();
+ }
+
+ @Override
+ public RawIterator apply(
+ Context ctx,
+ AnyValue[] input,
+ ResourceMonitor resourceMonitor
+ ) throws ProcedureException {
+ return this.procedure.apply(ctx, input);
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableUserAggregationFunctionImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableUserAggregationFunctionImpl.java
new file mode 100644
index 00000000000..b7a79d76f37
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CallableUserAggregationFunctionImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompatUserAggregator;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.UserAggregationReducer;
+import org.neo4j.internal.kernel.api.procs.UserAggregationUpdater;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableUserAggregationFunctionImpl implements CallableUserAggregationFunction {
+ private final CompatUserAggregationFunction function;
+
+ CallableUserAggregationFunctionImpl(CompatUserAggregationFunction function) {
+ this.function = function;
+ }
+
+ @Override
+ public UserFunctionSignature signature() {
+ return this.function.signature();
+ }
+
+ @Override
+ public UserAggregationReducer createReducer(Context ctx) throws ProcedureException {
+ return new UserAggregatorImpl(this.function.create(ctx));
+ }
+
+ private static final class UserAggregatorImpl implements UserAggregationReducer, UserAggregationUpdater {
+ private final CompatUserAggregator aggregator;
+
+ private UserAggregatorImpl(CompatUserAggregator aggregator) {
+ this.aggregator = aggregator;
+ }
+
+ @Override
+ public UserAggregationUpdater newUpdater() {
+ return this;
+ }
+
+ @Override
+ public void update(AnyValue[] input) throws ProcedureException {
+ this.aggregator.update(input);
+ }
+
+ @Override
+ public void applyUpdates() {
+ }
+
+ @Override
+ public AnyValue result() throws ProcedureException {
+ return this.aggregator.result();
+ }
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatAccessModeImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatAccessModeImpl.java
new file mode 100644
index 00000000000..226f56cd1bb
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatAccessModeImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.CompatAccessMode;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.internal.kernel.api.RelTypeSupplier;
+import org.neo4j.internal.kernel.api.TokenSet;
+
+import java.util.function.Supplier;
+
+public class CompatAccessModeImpl extends CompatAccessMode {
+
+ CompatAccessModeImpl(CustomAccessMode custom) {
+ super(custom);
+ }
+
+ @Override
+ public boolean allowsReadNodeProperty(Supplier labels, int propertyKey) {
+ return custom.allowsReadNodeProperty(propertyKey);
+ }
+
+ @Override
+ public boolean allowsReadRelationshipProperty(RelTypeSupplier relType, int propertyKey) {
+ return custom.allowsReadRelationshipProperty(propertyKey);
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatGraphDatabaseAPIImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatGraphDatabaseAPIImpl.java
new file mode 100644
index 00000000000..a4c2fc7a6de
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatGraphDatabaseAPIImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.exceptions.Status;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.coreapi.TransactionExceptionMapper;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+final class CompatGraphDatabaseAPIImpl extends GdsGraphDatabaseAPI {
+
+ CompatGraphDatabaseAPIImpl(DatabaseManagementService dbms) {
+ super(dbms);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return api.isAvailable();
+ }
+
+ @Override
+ public TopologyGraphDbmsModel.HostedOnMode mode() {
+ // NOTE: This means we can never start clusters locally, which is probably fine since:
+ // 1) We never did this before
+ // 2) We only use this for tests and benchmarks
+ return TopologyGraphDbmsModel.HostedOnMode.SINGLE;
+ }
+
+ @Override
+ public InternalTransaction beginTransaction(
+ KernelTransaction.Type type,
+ LoginContext loginContext,
+ ClientConnectionInfo clientInfo,
+ long timeout,
+ TimeUnit unit,
+ Consumer terminationCallback,
+ TransactionExceptionMapper transactionExceptionMapper
+ ) {
+ return api.beginTransaction(
+ type,
+ loginContext,
+ clientInfo,
+ timeout,
+ unit,
+ terminationCallback,
+ transactionExceptionMapper
+ );
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatIndexQueryImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatIndexQueryImpl.java
new file mode 100644
index 00000000000..11d2514b955
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatIndexQueryImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+
+final class CompatIndexQueryImpl implements CompatIndexQuery {
+ final PropertyIndexQuery indexQuery;
+
+ CompatIndexQueryImpl(PropertyIndexQuery indexQuery) {
+ this.indexQuery = indexQuery;
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatUsernameAuthSubjectImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatUsernameAuthSubjectImpl.java
new file mode 100644
index 00000000000..79a8b581efd
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompatUsernameAuthSubjectImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.CompatUsernameAuthSubject;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+
+final class CompatUsernameAuthSubjectImpl extends CompatUsernameAuthSubject {
+
+ CompatUsernameAuthSubjectImpl(String username, AuthSubject authSubject) {
+ super(username, authSubject);
+ }
+
+ @Override
+ public String executingUser() {
+ return username;
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompositeNodeCursorImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompositeNodeCursorImpl.java
new file mode 100644
index 00000000000..98978df157a
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/CompositeNodeCursorImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+
+import java.util.List;
+
+public final class CompositeNodeCursorImpl extends CompositeNodeCursor {
+
+ CompositeNodeCursorImpl(List cursors, int[] labelIds) {
+ super(cursors, labelIds);
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseLayoutImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseLayoutImpl.java
new file mode 100644
index 00000000000..1dda86e46e0
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseLayoutImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.io.layout.DatabaseLayout;
+
+import java.nio.file.Path;
+
+public class GdsDatabaseLayoutImpl implements GdsDatabaseLayout {
+ private final DatabaseLayout databaseLayout;
+
+ public GdsDatabaseLayoutImpl(DatabaseLayout databaseLayout) {this.databaseLayout = databaseLayout;}
+
+ @Override
+ public Path databaseDirectory() {
+ return databaseLayout.databaseDirectory();
+ }
+
+ @Override
+ public Path getTransactionLogsDirectory() {
+ return databaseLayout.getTransactionLogsDirectory();
+ }
+
+ @Override
+ public Path metadataStore() {
+ return databaseLayout.metadataStore();
+ }
+
+ public DatabaseLayout databaseLayout() {
+ return databaseLayout;
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseManagementServiceBuilderImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseManagementServiceBuilderImpl.java
new file mode 100644
index 00000000000..665ae3d6cda
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/GdsDatabaseManagementServiceBuilderImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.api.DatabaseManagementServiceBuilderImplementation;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.graphdb.config.Setting;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+public class GdsDatabaseManagementServiceBuilderImpl implements GdsDatabaseManagementServiceBuilder {
+
+ private final DatabaseManagementServiceBuilderImplementation dbmsBuilder;
+
+ GdsDatabaseManagementServiceBuilderImpl(Path storeDir) {
+ this.dbmsBuilder = new DatabaseManagementServiceBuilderImplementation(storeDir);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfigRaw(Map configMap) {
+ dbmsBuilder.setConfigRaw(configMap);
+ return this;
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfig(Setting setting, S value) {
+ dbmsBuilder.setConfig(setting, value);
+ return this;
+ }
+
+ @Override
+ public DatabaseManagementService build() {
+ return dbmsBuilder.build();
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..7719f97a641
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_11;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ return new Neo4jProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.11";
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyImpl.java
new file mode 100644
index 00000000000..05a406402a8
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/Neo4jProxyImpl.java
@@ -0,0 +1,986 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.neo4j.common.DependencyResolver;
+import org.neo4j.common.EntityType;
+import org.neo4j.configuration.BootloaderSettings;
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.GraphDatabaseSettings;
+import org.neo4j.configuration.SettingValueParsers;
+import org.neo4j.configuration.connectors.ConnectorPortRegister;
+import org.neo4j.configuration.connectors.ConnectorType;
+import org.neo4j.configuration.helpers.DatabaseNameValidator;
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.fabric.FabricDatabaseManager;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.gds.compat.CompatExecutionMonitor;
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.gds.compat.CompatInput;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat.InputEntityIdVisitor;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.gds.compat.TestLog;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.internal.batchimport.AdditionalInitialIds;
+import org.neo4j.internal.batchimport.BatchImporter;
+import org.neo4j.internal.batchimport.BatchImporterFactory;
+import org.neo4j.internal.batchimport.Configuration;
+import org.neo4j.internal.batchimport.IndexConfig;
+import org.neo4j.internal.batchimport.InputIterable;
+import org.neo4j.internal.batchimport.Monitor;
+import org.neo4j.internal.batchimport.input.Collector;
+import org.neo4j.internal.batchimport.input.IdType;
+import org.neo4j.internal.batchimport.input.Input;
+import org.neo4j.internal.batchimport.input.InputEntityVisitor;
+import org.neo4j.internal.batchimport.input.PropertySizeCalculator;
+import org.neo4j.internal.batchimport.input.ReadableGroups;
+import org.neo4j.internal.batchimport.staging.ExecutionMonitor;
+import org.neo4j.internal.batchimport.staging.StageExecution;
+import org.neo4j.internal.helpers.HostnamePort;
+import org.neo4j.internal.id.IdGenerator;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.IndexQueryConstraints;
+import org.neo4j.internal.kernel.api.IndexReadSession;
+import org.neo4j.internal.kernel.api.NodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.NodeValueIndexCursor;
+import org.neo4j.internal.kernel.api.PropertyCursor;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+import org.neo4j.internal.kernel.api.QueryContext;
+import org.neo4j.internal.kernel.api.Read;
+import org.neo4j.internal.kernel.api.RelationshipScanCursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.internal.kernel.api.TokenPredicate;
+import org.neo4j.internal.kernel.api.TokenSet;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.FieldSignature;
+import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.internal.kernel.api.procs.QualifiedName;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.internal.kernel.api.security.AccessMode;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+import org.neo4j.internal.kernel.api.security.ReadSecurityPropertyProvider;
+import org.neo4j.internal.kernel.api.security.SecurityContext;
+import org.neo4j.internal.recordstorage.RecordIdType;
+import org.neo4j.internal.schema.IndexCapability;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexOrder;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.layout.recordstorage.RecordDatabaseLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.context.EmptyVersionContextSupplier;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.KernelTransactionHandle;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
+import org.neo4j.kernel.database.NormalizedDatabaseName;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.index.schema.IndexImporterFactoryImpl;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.TransactionalContext;
+import org.neo4j.kernel.impl.query.TransactionalContextFactory;
+import org.neo4j.kernel.impl.store.RecordStore;
+import org.neo4j.kernel.impl.store.format.RecordFormatSelector;
+import org.neo4j.kernel.impl.store.format.RecordFormats;
+import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
+import org.neo4j.kernel.impl.transaction.log.EmptyLogTailMetadata;
+import org.neo4j.kernel.impl.transaction.log.files.TransactionLogInitializer;
+import org.neo4j.logging.Log;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.EmptyMemoryTracker;
+import org.neo4j.procedure.Mode;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.ssl.config.SslPolicyLoader;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.util.Bits;
+import org.neo4j.values.storable.TextArray;
+import org.neo4j.values.storable.ValueCategory;
+import org.neo4j.values.storable.Values;
+import org.neo4j.values.virtual.MapValue;
+import org.neo4j.values.virtual.NodeValue;
+import org.neo4j.values.virtual.VirtualValues;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.lang.String.format;
+import static org.neo4j.gds.compat.InternalReadOps.countByIdGenerator;
+import static org.neo4j.io.pagecache.context.EmptyVersionContextSupplier.EMPTY;
+
+public final class Neo4jProxyImpl implements Neo4jProxyApi {
+
+ @Override
+ public GdsGraphDatabaseAPI newDb(DatabaseManagementService dbms) {
+ return new CompatGraphDatabaseAPIImpl(dbms);
+ }
+
+ @Override
+ public String validateExternalDatabaseName(String databaseName) {
+ var normalizedName = new NormalizedDatabaseName(databaseName);
+ DatabaseNameValidator.validateExternalDatabaseName(normalizedName);
+ return normalizedName.name();
+ }
+
+ @Override
+ public AccessMode accessMode(CustomAccessMode customAccessMode) {
+ return new CompatAccessModeImpl(customAccessMode) {
+ @Override
+ public boolean allowsReadNodeProperty(
+ Supplier labels,
+ int propertyKey,
+ ReadSecurityPropertyProvider propertyProvider
+ ) {
+ return custom.allowsReadNodeProperty(propertyKey);
+ }
+ };
+ }
+ @Override
+ public String username(AuthSubject subject) {
+ return subject.executingUser();
+ }
+
+ @Override
+ public SecurityContext securityContext(
+ String username,
+ AuthSubject authSubject,
+ AccessMode mode,
+ String databaseName
+ ) {
+ return new SecurityContext(
+ new CompatUsernameAuthSubjectImpl(username, authSubject),
+ mode,
+ // GDS is always operating from an embedded context
+ ClientConnectionInfo.EMBEDDED_CONNECTION,
+ databaseName
+ );
+ }
+
+ @Override
+ public long getHighId(RecordStore extends AbstractBaseRecord> recordStore) {
+ return recordStore.getIdGenerator().getHighId();
+ }
+
+ @Override
+ public List> entityCursorScan(
+ KernelTransaction transaction,
+ int[] labelIds,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelIds);
+ } else {
+ var read = transaction.dataRead();
+ return Arrays
+ .stream(labelIds)
+ .mapToObj(read::nodeLabelScan)
+ .map(scan -> scanToStoreScan(scan, batchSize))
+ .collect(Collectors.toList());
+ }
+ }
+
+ @Override
+ public PropertyCursor allocatePropertyCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocatePropertyCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public PropertyReference propertyReference(NodeCursor nodeCursor) {
+ return ReferencePropertyReference.of(nodeCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference propertyReference(RelationshipScanCursor relationshipScanCursor) {
+ return ReferencePropertyReference.of(relationshipScanCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference noPropertyReference() {
+ return ReferencePropertyReference.empty();
+ }
+
+ @Override
+ public void nodeProperties(
+ KernelTransaction kernelTransaction,
+ long nodeReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .nodeProperties(nodeReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public void relationshipProperties(
+ KernelTransaction kernelTransaction,
+ long relationshipReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .relationshipProperties(relationshipReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public NodeCursor allocateNodeCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public RelationshipScanCursor allocateRelationshipScanCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateRelationshipScanCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeLabelIndexCursor allocateNodeLabelIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeLabelIndexCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeValueIndexCursor allocateNodeValueIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocateNodeValueIndexCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public boolean hasNodeLabelIndex(KernelTransaction kernelTransaction) {
+ return NodeLabelIndexLookupImpl.hasNodeLabelIndex(kernelTransaction);
+ }
+
+ @Override
+ public StoreScan nodeLabelIndexScan(
+ KernelTransaction transaction,
+ int labelId,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelId).get(0);
+ } else {
+ var read = transaction.dataRead();
+ return scanToStoreScan(read.nodeLabelScan(labelId), batchSize);
+ }
+ }
+
+ @Override
+ public StoreScan scanToStoreScan(Scan scan, int batchSize) {
+ return new ScanBasedStoreScanImpl<>(scan, batchSize);
+ }
+
+ private List> partitionedNodeLabelIndexScan(
+ KernelTransaction transaction,
+ int batchSize,
+ int... labelIds
+ ) {
+ var indexDescriptor = NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ );
+
+ if (indexDescriptor == IndexDescriptor.NO_INDEX) {
+ throw new IllegalStateException("There is no index that can back a node label scan.");
+ }
+
+ var read = transaction.dataRead();
+
+ // Our current strategy is to select the token with the highest count
+ // and use that one as the driving partitioned index scan. The partitions
+ // of all other partitioned index scans will be aligned to that one.
+ int maxToken = labelIds[0];
+ long maxCount = read.countsForNodeWithoutTxState(labelIds[0]);
+
+ for (int i = 1; i < labelIds.length; i++) {
+ long count = read.countsForNodeWithoutTxState(labelIds[i]);
+ if (count > maxCount) {
+ maxCount = count;
+ maxToken = labelIds[i];
+ }
+ }
+
+ int numberOfPartitions = PartitionedStoreScan.getNumberOfPartitions(maxCount, batchSize);
+
+ try {
+ var session = read.tokenReadSession(indexDescriptor);
+
+ var partitionedScan = read.nodeLabelScan(
+ session,
+ numberOfPartitions,
+ transaction.cursorContext(),
+ new TokenPredicate(maxToken)
+ );
+
+ var scans = new ArrayList>(labelIds.length);
+ scans.add(new PartitionedStoreScan(partitionedScan));
+
+ // Initialize the remaining index scans with the partitioning of the first scan.
+ for (int labelToken : labelIds) {
+ if (labelToken != maxToken) {
+ var scan = read.nodeLabelScan(session, partitionedScan, new TokenPredicate(labelToken));
+ scans.add(new PartitionedStoreScan(scan));
+ }
+ }
+
+ return scans;
+ } catch (KernelException e) {
+ // should not happen, we check for the index existence and applicability
+ // before reading it
+ throw new RuntimeException("Unexpected error while initialising reading from node label index", e);
+ }
+ }
+
+ @Override
+ public CompatIndexQuery rangeIndexQuery(
+ int propertyKeyId,
+ double from,
+ boolean fromInclusive,
+ double to,
+ boolean toInclusive
+ ) {
+ return new CompatIndexQueryImpl(PropertyIndexQuery.range(propertyKeyId, from, fromInclusive, to, toInclusive));
+ }
+
+ @Override
+ public CompatIndexQuery rangeAllIndexQuery(int propertyKeyId) {
+ var rangePredicate = PropertyIndexQuery.range(
+ propertyKeyId,
+ Values.doubleValue(Double.NEGATIVE_INFINITY),
+ true,
+ Values.doubleValue(Double.POSITIVE_INFINITY),
+ true
+ );
+ return new CompatIndexQueryImpl(rangePredicate);
+ }
+
+ @Override
+ public void nodeIndexSeek(
+ Read dataRead,
+ IndexReadSession index,
+ NodeValueIndexCursor cursor,
+ IndexOrder indexOrder,
+ boolean needsValues,
+ CompatIndexQuery query
+ ) throws KernelException {
+ var indexQueryConstraints = indexOrder == IndexOrder.NONE
+ ? IndexQueryConstraints.unordered(needsValues)
+ : IndexQueryConstraints.constrained(indexOrder, needsValues);
+
+ dataRead.nodeIndexSeek(
+ (QueryContext) dataRead,
+ index,
+ cursor,
+ indexQueryConstraints,
+ ((CompatIndexQueryImpl) query).indexQuery
+ );
+ }
+
+ @Override
+ public CompositeNodeCursor compositeNodeCursor(List cursors, int[] labelIds) {
+ return new CompositeNodeCursorImpl(cursors, labelIds);
+ }
+
+ @Override
+ public Configuration batchImporterConfig(
+ int batchSize,
+ int writeConcurrency,
+ Optional pageCacheMemory,
+ boolean highIO,
+ IndexConfig indexConfig
+ ) {
+ return new org.neo4j.internal.batchimport.Configuration() {
+ @Override
+ public int batchSize() {
+ return batchSize;
+ }
+
+ @Override
+ public int maxNumberOfWorkerThreads() {
+ return writeConcurrency;
+ }
+
+ @Override
+ public boolean highIO() {
+ return highIO;
+ }
+
+ @Override
+ public IndexConfig indexConfig() {
+ return indexConfig;
+ }
+ };
+ }
+
+ @Override
+ public int writeConcurrency(Configuration batchImportConfiguration) {
+ return batchImportConfiguration.maxNumberOfWorkerThreads();
+ }
+
+ @Override
+ public BatchImporter instantiateBatchImporter(
+ BatchImporterFactory factory,
+ GdsDatabaseLayout directoryStructure,
+ FileSystemAbstraction fileSystem,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ ExecutionMonitor executionMonitor,
+ AdditionalInitialIds additionalInitialIds,
+ Config dbConfig,
+ RecordFormats recordFormats,
+ JobScheduler jobScheduler,
+ Collector badCollector
+ ) {
+ dbConfig.set(GraphDatabaseSettings.db_format, recordFormats.name());
+ var databaseLayout = ((GdsDatabaseLayoutImpl) directoryStructure).databaseLayout();
+ return factory.instantiate(
+ databaseLayout,
+ fileSystem,
+ pageCacheTracer,
+ configuration,
+ logService,
+ executionMonitor,
+ additionalInitialIds,
+ new EmptyLogTailMetadata(dbConfig),
+ dbConfig,
+ Monitor.NO_MONITOR,
+ jobScheduler,
+ badCollector,
+ TransactionLogInitializer.getLogFilesInitializer(),
+ new IndexImporterFactoryImpl(),
+ EmptyMemoryTracker.INSTANCE,
+ new CursorContextFactory(PageCacheTracer.NULL, EmptyVersionContextSupplier.EMPTY)
+ );
+ }
+
+ @Override
+ public Input batchInputFrom(CompatInput compatInput) {
+ return new InputFromCompatInput(compatInput);
+ }
+
+ @Override
+ public InputEntityIdVisitor.Long inputEntityLongIdVisitor(IdType idType, ReadableGroups groups) {
+ switch (idType) {
+ case ACTUAL -> {
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id);
+ }
+ };
+ }
+ case INTEGER -> {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+ default -> throw new IllegalStateException("Unexpected value: " + idType);
+ }
+ }
+
+ @Override
+ public InputEntityIdVisitor.String inputEntityStringIdVisitor(ReadableGroups groups) {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.String() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, String id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, String id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, String id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+
+ @Override
+ public Setting additionalJvm() {
+ return BootloaderSettings.additional_jvm;
+ }
+
+ @Override
+ public Setting pageCacheMemory() {
+ return GraphDatabaseSettings.pagecache_memory;
+ }
+
+ @Override
+ public Long pageCacheMemoryValue(String value) {
+ return SettingValueParsers.BYTES.parse(value);
+ }
+
+ @Override
+ public ProcedureSignature procedureSignature(
+ QualifiedName name,
+ List inputSignature,
+ List outputSignature,
+ Mode mode,
+ boolean admin,
+ String deprecated,
+ String description,
+ String warning,
+ boolean eager,
+ boolean caseInsensitive,
+ boolean systemProcedure,
+ boolean internal,
+ boolean allowExpiredCredentials,
+ boolean threadSafe
+ ) {
+ return new ProcedureSignature(
+ name,
+ inputSignature,
+ outputSignature,
+ mode,
+ admin,
+ deprecated,
+ description,
+ warning,
+ eager,
+ caseInsensitive,
+ systemProcedure,
+ internal,
+ allowExpiredCredentials,
+ threadSafe
+ );
+ }
+
+ @Override
+ public long getHighestPossibleNodeCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.NODE).orElseGet(read::nodesGetCount);
+ }
+
+ @Override
+ public long getHighestPossibleRelationshipCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.RELATIONSHIP).orElseGet(read::relationshipsGetCount);
+ }
+
+ @Override
+ public String versionLongToString(long storeVersion) {
+ // copied from org.neo4j.kernel.impl.store.LegacyMetadataHandler.versionLongToString which is private
+ if (storeVersion == -1) {
+ return "Unknown";
+ }
+ Bits bits = Bits.bitsFromLongs(new long[]{storeVersion});
+ int length = bits.getShort(8);
+ if (length == 0 || length > 7) {
+ throw new IllegalArgumentException(format(
+ Locale.ENGLISH,
+ "The read version string length %d is not proper.",
+ length
+ ));
+ }
+ char[] result = new char[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = (char) bits.getShort(8);
+ }
+ return new String(result);
+ }
+
+ private static final class InputFromCompatInput implements Input {
+ private final CompatInput delegate;
+
+ private InputFromCompatInput(CompatInput delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public InputIterable nodes(Collector badCollector) {
+ return delegate.nodes(badCollector);
+ }
+
+ @Override
+ public InputIterable relationships(Collector badCollector) {
+ return delegate.relationships(badCollector);
+ }
+
+ @Override
+ public IdType idType() {
+ return delegate.idType();
+ }
+
+ @Override
+ public ReadableGroups groups() {
+ return delegate.groups();
+ }
+
+ @Override
+ public Estimates calculateEstimates(PropertySizeCalculator propertySizeCalculator) throws IOException {
+ return delegate.calculateEstimates((values, kernelTransaction) -> propertySizeCalculator.calculateSize(
+ values,
+ kernelTransaction.cursorContext(),
+ kernelTransaction.memoryTracker()
+ ));
+ }
+ }
+
+ @Override
+ public TestLog testLog() {
+ return new TestLogImpl();
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getUserLog(LogService logService, Class> loggingClass) {
+ return logService.getUserLog(loggingClass);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getInternalLog(LogService logService, Class> loggingClass) {
+ return logService.getInternalLog(loggingClass);
+ }
+
+ @Override
+ public NodeValue nodeValue(long id, TextArray labels, MapValue properties) {
+ return VirtualValues.nodeValue(id, String.valueOf(id), labels, properties);
+ }
+
+ @Override
+ public Relationship virtualRelationship(long id, Node startNode, Node endNode, RelationshipType type) {
+ return new VirtualRelationshipImpl(id, startNode, endNode, type);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder databaseManagementServiceBuilder(Path storeDir) {
+ return new GdsDatabaseManagementServiceBuilderImpl(storeDir);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats selectRecordFormatForStore(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ return RecordFormatSelector.selectForStore(
+ (RecordDatabaseLayout) databaseLayout,
+ fs,
+ pageCache,
+ logService.getInternalLogProvider(),
+ new CursorContextFactory(pageCacheTracer, EMPTY)
+ );
+ }
+
+ @Override
+ public boolean isNotNumericIndex(IndexCapability indexCapability) {
+ return !indexCapability.areValueCategoriesAccepted(ValueCategory.NUMBER);
+ }
+
+ @Override
+ public void setAllowUpgrades(Config.Builder configBuilder, boolean value) {
+ }
+
+ @Override
+ public String defaultRecordFormatSetting() {
+ return GraphDatabaseSettings.db_format.defaultValue();
+ }
+
+ @Override
+ public void configureRecordFormat(Config.Builder configBuilder, String recordFormat) {
+ var databaseRecordFormat = recordFormat.toLowerCase(Locale.ENGLISH);
+ configBuilder.set(GraphDatabaseSettings.db_format, databaseRecordFormat);
+ }
+
+ @Override
+ public GdsDatabaseLayout databaseLayout(Config config, String databaseName) {
+ var storageEngineFactory = StorageEngineFactory.selectStorageEngine(config);
+ var dbLayout = neo4jLayout(config).databaseLayout(databaseName);
+ var databaseLayout = storageEngineFactory.formatSpecificDatabaseLayout(dbLayout);
+ return new GdsDatabaseLayoutImpl(databaseLayout);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Neo4jLayout neo4jLayout(Config config) {
+ return Neo4jLayout.of(config);
+ }
+
+ @Override
+ public BoltTransactionRunner, ?> boltTransactionRunner() {
+ return new BoltTransactionRunnerImpl();
+ }
+
+ @Override
+ public HostnamePort getLocalBoltAddress(ConnectorPortRegister connectorPortRegister) {
+ return connectorPortRegister.getLocalAddress(ConnectorType.BOLT);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public SslPolicyLoader createSllPolicyLoader(
+ FileSystemAbstraction fileSystem,
+ Config config,
+ LogService logService
+ ) {
+ return SslPolicyLoader.create(fileSystem, config, logService.getInternalLogProvider());
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats recordFormatSelector(
+ String databaseName,
+ Config databaseConfig,
+ FileSystemAbstraction fs,
+ LogService logService,
+ GraphDatabaseService databaseService
+ ) {
+ var neo4jLayout = Neo4jLayout.of(databaseConfig);
+ var recordDatabaseLayout = RecordDatabaseLayout.of(neo4jLayout, databaseName);
+ return RecordFormatSelector.selectForStoreOrConfigForNewDbs(
+ databaseConfig,
+ recordDatabaseLayout,
+ fs,
+ GraphDatabaseApiProxy.resolveDependency(databaseService, PageCache.class),
+ logService.getInternalLogProvider(),
+ GraphDatabaseApiProxy.resolveDependency(databaseService, CursorContextFactory.class)
+ );
+ }
+
+ @Override
+ public ExecutionMonitor executionMonitor(CompatExecutionMonitor compatExecutionMonitor) {
+ return new ExecutionMonitor.Adapter(
+ compatExecutionMonitor.checkIntervalMillis(),
+ TimeUnit.MILLISECONDS
+ ) {
+
+ @Override
+ public void initialize(DependencyResolver dependencyResolver) {
+ compatExecutionMonitor.initialize(dependencyResolver);
+ }
+
+ @Override
+ public void start(StageExecution execution) {
+ compatExecutionMonitor.start(execution);
+ }
+
+ @Override
+ public void end(StageExecution execution, long totalTimeMillis) {
+ compatExecutionMonitor.end(execution, totalTimeMillis);
+ }
+
+ @Override
+ public void done(boolean successful, long totalTimeMillis, String additionalInformation) {
+ compatExecutionMonitor.done(successful, totalTimeMillis, additionalInformation);
+ }
+
+ @Override
+ public void check(StageExecution execution) {
+ compatExecutionMonitor.check(execution);
+ }
+ };
+ }
+
+ @Override
+ @SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE") // We assign nulls because it makes the code more readable
+ public UserFunctionSignature userFunctionSignature(
+ QualifiedName name,
+ List inputSignature,
+ Neo4jTypes.AnyType type,
+ String description,
+ boolean internal,
+ boolean threadSafe,
+ Optional deprecatedBy
+ ) {
+ String category = null; // No predefined categpry (like temporal or math)
+ var caseInsensitive = false; // case sensitive name match
+ var isBuiltIn = false; // is built in; never true for GDS
+
+ return new UserFunctionSignature(
+ name,
+ inputSignature,
+ type,
+ deprecatedBy.orElse(null),
+ description,
+ category,
+ caseInsensitive,
+ isBuiltIn,
+ internal,
+ threadSafe
+ );
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableProcedure callableProcedure(CompatCallableProcedure procedure) {
+ return new CallableProcedureImpl(procedure);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableUserAggregationFunction callableUserAggregationFunction(CompatUserAggregationFunction function) {
+ return new CallableUserAggregationFunctionImpl(function);
+ }
+
+ @Override
+ public long transactionId(KernelTransactionHandle kernelTransactionHandle) {
+ return kernelTransactionHandle.getTransactionSequenceNumber();
+ }
+
+ @Override
+ public void reserveNeo4jIds(IdGeneratorFactory generatorFactory, int size, CursorContext cursorContext) {
+ IdGenerator idGenerator = generatorFactory.get(RecordIdType.NODE);
+
+ idGenerator.nextConsecutiveIdRange(size, false, cursorContext);
+ }
+
+ @Override
+ public TransactionalContext newQueryContext(
+ TransactionalContextFactory contextFactory,
+ InternalTransaction tx,
+ String queryText,
+ MapValue queryParameters
+ ) {
+ return contextFactory.newContext(tx, queryText, queryParameters, QueryExecutionConfiguration.DEFAULT_CONFIG);
+ }
+
+ @Override
+ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
+ var databaseManager = GraphDatabaseApiProxy.resolveDependency(databaseService, FabricDatabaseManager.class);
+ return databaseManager.isFabricDatabase(GraphDatabaseApiProxy.databaseId(databaseService));
+ }
+
+ @Override
+ public T lookupComponentProvider(Context ctx, Class component, boolean safe) throws ProcedureException {
+ var globalProcedures = GraphDatabaseApiProxy.resolveDependency(
+ ctx.dependencyResolver(),
+ GlobalProcedures.class
+ );
+ return globalProcedures.getCurrentView().lookupComponentProvider(component, safe).apply(ctx);
+ }
+
+ @Override
+ public GlobalProcedureRegistry globalProcedureRegistry(GlobalProcedures globalProcedures) {
+ return new GlobalProcedureRegistry() {
+ @Override
+ public Set getAllProcedures() {
+ return globalProcedures.getCurrentView().getAllProcedures();
+ }
+
+ @Override
+ public Stream getAllNonAggregatingFunctions() {
+ return globalProcedures.getCurrentView().getAllNonAggregatingFunctions();
+ }
+
+ @Override
+ public Stream getAllAggregatingFunctions() {
+ return globalProcedures.getCurrentView().getAllAggregatingFunctions();
+ }
+ };
+ }
+
+ private static final DependencyResolver EMPTY_DEPENDENCY_RESOLVER = new DependencyResolver.Adapter() {
+ @Override
+ public T resolveDependency(Class type, SelectionStrategy selector) {
+ return null;
+ }
+
+ @Override
+ public boolean containsDependency(Class> type) {
+ return false;
+ }
+ };
+
+ @Override
+ public DependencyResolver emptyDependencyResolver() {
+ return EMPTY_DEPENDENCY_RESOLVER;
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/NodeLabelIndexLookupImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/NodeLabelIndexLookupImpl.java
new file mode 100644
index 00000000000..5465d3261a2
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/NodeLabelIndexLookupImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.common.EntityType;
+import org.neo4j.internal.kernel.api.InternalIndexState;
+import org.neo4j.internal.kernel.api.SchemaRead;
+import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexType;
+import org.neo4j.internal.schema.SchemaDescriptor;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class NodeLabelIndexLookupImpl {
+
+ static boolean hasNodeLabelIndex(KernelTransaction transaction) {
+ return NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ ) != IndexDescriptor.NO_INDEX;
+ }
+
+ static IndexDescriptor findUsableMatchingIndex(
+ KernelTransaction transaction,
+ SchemaDescriptor schemaDescriptor
+ ) {
+ var schemaRead = transaction.schemaRead();
+ var iterator = schemaRead.index(schemaDescriptor);
+ while (iterator.hasNext()) {
+ var index = iterator.next();
+ if (index.getIndexType() == IndexType.LOOKUP && indexIsOnline(schemaRead, index)) {
+ return index;
+ }
+ }
+ return IndexDescriptor.NO_INDEX;
+ }
+
+ private static boolean indexIsOnline(SchemaRead schemaRead, IndexDescriptor index) {
+ var state = InternalIndexState.FAILED;
+ try {
+ state = schemaRead.indexGetState(index);
+ } catch (IndexNotFoundKernelException e) {
+ // Well the index should always exist here, but if we didn't find it while checking the state,
+ // then we obviously don't want to use it.
+ }
+ return state == InternalIndexState.ONLINE;
+ }
+
+ private NodeLabelIndexLookupImpl() {}
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/PartitionedStoreScan.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/PartitionedStoreScan.java
new file mode 100644
index 00000000000..cbd2f63fcf5
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/PartitionedStoreScan.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.PartitionedScan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class PartitionedStoreScan implements StoreScan {
+ private final PartitionedScan scan;
+
+ PartitionedStoreScan(PartitionedScan scan) {
+ this.scan = scan;
+ }
+
+ static int getNumberOfPartitions(long nodeCount, int batchSize) {
+ int numberOfPartitions;
+ if (nodeCount > 0) {
+ // ceil div to try to get enough partitions so a single one does
+ // not include more nodes than batchSize
+ long partitions = ((nodeCount - 1) / batchSize) + 1;
+
+ // value must be positive
+ if (partitions < 1) {
+ partitions = 1;
+ }
+
+ numberOfPartitions = (int) Long.min(Integer.MAX_VALUE, partitions);
+ } else {
+ // we have no partitions to scan, but the value must still be positive
+ numberOfPartitions = 1;
+ }
+ return numberOfPartitions;
+ }
+
+ @Override
+ public boolean reserveBatch(NodeLabelIndexCursor cursor, KernelTransaction ktx) {
+ return scan.reservePartition(cursor, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ReferencePropertyReference.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ReferencePropertyReference.java
new file mode 100644
index 00000000000..7ec85a1d19c
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ReferencePropertyReference.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.storageengine.api.Reference;
+
+import java.util.Objects;
+
+public final class ReferencePropertyReference implements PropertyReference {
+
+ private static final PropertyReference EMPTY = new ReferencePropertyReference(null);
+
+ public final Reference reference;
+
+ private ReferencePropertyReference(Reference reference) {
+ this.reference = reference;
+ }
+
+ public static PropertyReference of(Reference reference) {
+ return new ReferencePropertyReference(Objects.requireNonNull(reference));
+ }
+
+ public static PropertyReference empty() {
+ return EMPTY;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return reference == null;
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ScanBasedStoreScanImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ScanBasedStoreScanImpl.java
new file mode 100644
index 00000000000..fbee3ca33b1
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/ScanBasedStoreScanImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+public final class ScanBasedStoreScanImpl implements StoreScan {
+ private final Scan scan;
+ private final int batchSize;
+
+ public ScanBasedStoreScanImpl(Scan scan, int batchSize) {
+ this.scan = scan;
+ this.batchSize = batchSize;
+ }
+
+ @Override
+ public boolean reserveBatch(C cursor, KernelTransaction ktx) {
+ return scan.reserveBatch(cursor, batchSize, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..0782eebff8d
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_11;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ return new SettingProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.11";
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyImpl.java
new file mode 100644
index 00000000000..965caa2d66d
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/SettingProxyImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.SettingBuilder;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.DatabaseMode;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.kernel.impl.factory.GraphDatabaseFacade;
+import org.neo4j.kernel.internal.GraphDatabaseAPI;
+
+public class SettingProxyImpl implements SettingProxyApi {
+
+ @Override
+ public Setting setting(org.neo4j.gds.compat.Setting setting) {
+ var builder = SettingBuilder.newBuilder(setting.name(), setting.parser(), setting.defaultValue());
+ if (setting.dynamic()) {
+ builder = builder.dynamic();
+ }
+ if (setting.immutable()) {
+ builder = builder.immutable();
+ }
+ setting.dependency().ifPresent(builder::setDependency);
+ setting.constraints().forEach(builder::addConstraint);
+ return builder.build();
+ }
+
+ @Override
+ public DatabaseMode databaseMode(Config config, GraphDatabaseService databaseService) {
+ return switch (((GraphDatabaseAPI) databaseService).mode()) {
+ case RAFT -> DatabaseMode.CORE;
+ case REPLICA -> DatabaseMode.READ_REPLICA;
+ case SINGLE -> DatabaseMode.SINGLE;
+ case VIRTUAL -> throw new UnsupportedOperationException("What's a virtual database anyway?");
+ };
+ }
+
+ @Override
+ public void setDatabaseMode(Config config, DatabaseMode databaseMode, GraphDatabaseService databaseService) {
+ // super hacky, there is no way to set the mode of a database without restarting it
+ if (!(databaseService instanceof GraphDatabaseFacade db)) {
+ throw new IllegalArgumentException(
+ "Cannot set database mode on a database that is not a GraphDatabaseFacade");
+ }
+ try {
+ var modeField = GraphDatabaseFacade.class.getDeclaredField("mode");
+ modeField.setAccessible(true);
+ modeField.set(db, switch (databaseMode) {
+ case CORE -> TopologyGraphDbmsModel.HostedOnMode.RAFT;
+ case READ_REPLICA -> TopologyGraphDbmsModel.HostedOnMode.REPLICA;
+ case SINGLE -> TopologyGraphDbmsModel.HostedOnMode.SINGLE;
+ });
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(
+ "Could not set the mode field because it no longer exists. This compat layer needs to be updated.",
+ e
+ );
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("Could not get the permissions to set the mode field.", e);
+ }
+ }
+
+ @Override
+ public String secondaryModeName() {
+ return "Secondary";
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/TestLogImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/TestLogImpl.java
new file mode 100644
index 00000000000..cbacd42e0d4
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/TestLogImpl.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.TestLog;
+
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+
+public class TestLogImpl implements TestLog {
+
+ private final ConcurrentMap> messages;
+
+ TestLogImpl() {
+ messages = new ConcurrentHashMap<>(3);
+ }
+
+ @Override
+ public void assertContainsMessage(String level, String fragment) {
+ if (!containsMessage(level, fragment)) {
+ throw new RuntimeException(
+ String.format(
+ Locale.US,
+ "Expected log output to contain `%s` for log level `%s`%nLog messages:%n%s",
+ fragment,
+ level,
+ String.join("\n", messages.get(level))
+ )
+ );
+ }
+ }
+
+ @Override
+ public boolean containsMessage(String level, String fragment) {
+ ConcurrentLinkedQueue messageList = messages.getOrDefault(level, new ConcurrentLinkedQueue<>());
+ return messageList.stream().anyMatch((message) -> message.contains(fragment));
+ }
+
+ @Override
+ public boolean hasMessages(String level) {
+ return !messages.getOrDefault(level, new ConcurrentLinkedQueue<>()).isEmpty();
+ }
+
+ @Override
+ public ArrayList getMessages(String level) {
+ return new ArrayList<>(messages.getOrDefault(level, new ConcurrentLinkedQueue<>()));
+ }
+
+ @SuppressForbidden(reason = "test log can print")
+ public void printMessages() {
+ System.out.println("TestLog Messages: " + messages);
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return true;
+ }
+
+ @Override
+ public void debug(String message) {
+ logMessage(DEBUG, message);
+ }
+
+ @Override
+ public void debug(String message, Throwable throwable) {
+ debug(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void debug(String format, Object... arguments) {
+ debug(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void info(String message) {
+ logMessage(INFO, message);
+ }
+
+ @Override
+ public void info(String message, Throwable throwable) {
+ info(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void info(String format, Object... arguments) {
+ info(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void warn(String message) {
+ logMessage(WARN, message);
+ }
+
+ @Override
+ public void warn(String message, Throwable throwable) {
+ warn(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void warn(String format, Object... arguments) {
+ warn(String.format(Locale.US, format, arguments));
+ }
+
+ @Override
+ public void error(String message) {
+ logMessage(ERROR, message);
+ }
+
+ @Override
+ public void error(String message, Throwable throwable) {
+ error(String.format(Locale.US, "%s - %s", message, throwable.getMessage()));
+ }
+
+ @Override
+ public void error(String format, Object... arguments) {
+ error(String.format(Locale.US, format, arguments));
+ }
+
+ private void logMessage(String level, String message) {
+ messages.computeIfAbsent(
+ level,
+ (ignore) -> new ConcurrentLinkedQueue<>()
+ ).add(message);
+ }
+}
diff --git a/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/VirtualRelationshipImpl.java b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/VirtualRelationshipImpl.java
new file mode 100644
index 00000000000..e14ab2d222e
--- /dev/null
+++ b/compatibility/5.11/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_511/VirtualRelationshipImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.VirtualRelationship;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.RelationshipType;
+
+public class VirtualRelationshipImpl extends VirtualRelationship {
+
+ VirtualRelationshipImpl(
+ long id,
+ Node startNode,
+ Node endNode,
+ RelationshipType type
+ ) {
+ super(id, startNode, endNode, type);
+ }
+
+ @Override
+ public String getElementId() {
+ return Long.toString(getId());
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/build.gradle b/compatibility/5.11/storage-engine-adapter/build.gradle
new file mode 100644
index 00000000000..0a21467ee37
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/build.gradle
@@ -0,0 +1,68 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Storage Engine Adapter 5.11'
+
+group = 'org.neo4j.gds'
+
+// for all 5.x versions
+if (ver.'neo4j'.startsWith('5.')) {
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java17']
+ }
+ }
+ }
+
+ dependencies {
+ annotationProcessor project(':annotations')
+ annotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.11'
+
+ compileOnly project(':annotations')
+ compileOnly project(':progress-tracking')
+ compileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.11'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.11'
+
+ implementation project(':core')
+ implementation project(':storage-engine-adapter-api')
+ implementation project(':config-api')
+ implementation project(':string-formatting')
+ }
+} else {
+ multiRelease {
+ targetVersions 11, 17
+ }
+
+ if (!project.hasProperty('no-forbidden-apis')) {
+ forbiddenApisJava17 {
+ exclude('**')
+ }
+ }
+
+ dependencies {
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+ compileOnly group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+ compileOnly group: 'org.neo4j', name: 'neo4j-kernel-api', version: ver.'neo4j'
+
+ implementation project(':neo4j-adapter')
+ implementation project(':storage-engine-adapter-api')
+
+ java17AnnotationProcessor project(':annotations')
+ java17AnnotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ java17AnnotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.11'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly project(':progress-tracking')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.11'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.11'
+
+ java17Implementation project(':core')
+ java17Implementation project(':storage-engine-adapter-api')
+ java17Implementation project(':config-api')
+ java17Implementation project(':string-formatting')
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java b/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java
new file mode 100644
index 00000000000..6b85ad71504
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.configuration.Config;
+import org.neo4j.dbms.database.readonly.DatabaseReadOnlyChecker;
+import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
+import org.neo4j.internal.id.IdController;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.schema.IndexConfigCompleter;
+import org.neo4j.internal.schema.SchemaRule;
+import org.neo4j.internal.schema.SchemaState;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.lock.LockService;
+import org.neo4j.logging.LogProvider;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.monitoring.DatabaseHealth;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+import org.neo4j.storageengine.api.ConstraintRuleAccessor;
+import org.neo4j.storageengine.api.LogVersionRepository;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageFilesState;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.TransactionIdStore;
+import org.neo4j.storageengine.migration.RollingUpgradeCompatibility;
+import org.neo4j.storageengine.migration.SchemaRuleMigrationAccess;
+import org.neo4j.storageengine.migration.StoreMigrationParticipant;
+import org.neo4j.token.TokenHolders;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+@ServiceProvider
+public class InMemoryStorageEngineFactory implements StorageEngineFactory {
+
+ @Override
+ public String name() {
+ return "unsupported511";
+ }
+
+ @Override
+ public StoreVersionCheck versionCheck(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(String storeVersion) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(StoreId storeId) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public RollingUpgradeCompatibility rollingUpgradeCompatibility() {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public List migrationParticipants(
+ FileSystemAbstraction fs,
+ Config config,
+ PageCache pageCache,
+ JobScheduler jobScheduler,
+ LogService logService,
+ PageCacheTracer cacheTracer,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public StorageEngine instantiate(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ TokenHolders tokenHolders,
+ SchemaState schemaState,
+ ConstraintRuleAccessor constraintSemantics,
+ IndexConfigCompleter indexConfigCompleter,
+ LockService lockService,
+ IdGeneratorFactory idGeneratorFactory,
+ IdController idController,
+ DatabaseHealth databaseHealth,
+ LogProvider internalLogProvider,
+ LogProvider userLogProvider,
+ RecoveryCleanupWorkCollector recoveryCleanupWorkCollector,
+ PageCacheTracer cacheTracer,
+ boolean createStoreIfNotExists,
+ DatabaseReadOnlyChecker readOnlyChecker,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public List listStorageFiles(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout) throws
+ IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public boolean storageExists(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout, PageCache pageCache) {
+ return false;
+ }
+
+ @Override
+ public TransactionIdStore readOnlyTransactionIdStore(
+ FileSystemAbstraction filySystem,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public LogVersionRepository readOnlyLogVersionRepository(
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public MetadataProvider transactionMetaDataStore(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ PageCacheTracer cacheTracer,
+ DatabaseReadOnlyChecker readOnlyChecker
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreId storeId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public void setStoreId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext,
+ StoreId storeId,
+ long upgradeTxChecksum,
+ long upgradeTxCommitTimestamp
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public void setExternalStoreUUID(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext,
+ UUID externalStoreId
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public Optional databaseIdUuid(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public SchemaRuleMigrationAccess schemaRuleMigrationAccess(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ Config config,
+ DatabaseLayout databaseLayout,
+ LogService logService,
+ String recordFormats,
+ PageCacheTracer cacheTracer,
+ CursorContext cursorContext,
+ MemoryTracker memoryTracker
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public List loadSchemaRules(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public StorageFilesState checkStoreFileState(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache
+ ) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public CommandReaderFactory commandReaderFactory() {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public DatabaseLayout databaseLayout(Neo4jLayout neo4jLayout, String databaseName) {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 00000000000..6d2f3217423
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.compat.StorageEngineProxyFactory;
+
+@ServiceProvider
+public class StorageEngineProxyFactoryImpl implements StorageEngineProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public StorageEngineProxyApi load() {
+ throw new UnsupportedOperationException("5.11 storage engine requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.11";
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCommandCreationContextImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCommandCreationContextImpl.java
new file mode 100644
index 00000000000..da81b6bbe34
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCommandCreationContextImpl.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.kernel.KernelVersionProvider;
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.storageengine.api.CommandCreationContext;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
+
+public class InMemoryCommandCreationContextImpl implements CommandCreationContext {
+
+ private final AtomicLong schemaTokens;
+ private final AtomicInteger propertyTokens;
+ private final AtomicInteger labelTokens;
+ private final AtomicInteger typeTokens;
+
+ InMemoryCommandCreationContextImpl() {
+ this.schemaTokens = new AtomicLong(0);
+ this.propertyTokens = new AtomicInteger(0);
+ this.labelTokens = new AtomicInteger(0);
+ this.typeTokens = new AtomicInteger(0);
+ }
+
+ @Override
+ public long reserveNode() {
+ throw new UnsupportedOperationException("Creating nodes is not supported");
+ }
+
+ @Override
+ public long reserveRelationship(
+ long sourceNode,
+ long targetNode,
+ int relationshipType,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ throw new UnsupportedOperationException("Creating relationships is not supported");
+ }
+
+ @Override
+ public long reserveSchema() {
+ return schemaTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reserveLabelTokenId() {
+ return labelTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reservePropertyKeyTokenId() {
+ return propertyTokens.getAndIncrement();
+ }
+
+ @Override
+ public int reserveRelationshipTypeTokenId() {
+ return typeTokens.getAndIncrement();
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void initialize(
+ KernelVersionProvider kernelVersionProvider,
+ CursorContext cursorContext,
+ StoreCursors storeCursors,
+ Supplier oldestActiveTransactionSequenceNumber,
+ ResourceLocker locks,
+ Supplier lockTracer
+ ) {
+
+ }
+
+ @Override
+ public KernelVersion kernelVersion() {
+ // NOTE: Double-check if this is still correct when you copy this into a new compat layer
+ return KernelVersion.getLatestVersion(Config.newBuilder().build());
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCountsStoreImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCountsStoreImpl.java
new file mode 100644
index 00000000000..6e3814395cd
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryCountsStoreImpl.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.documented.ReporterFactory;
+import org.neo4j.counts.CountsStore;
+import org.neo4j.counts.CountsUpdater;
+import org.neo4j.counts.CountsVisitor;
+import org.neo4j.gds.NodeLabel;
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.internal.helpers.progress.ProgressMonitorFactory;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.tracing.FileFlushEvent;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.token.TokenHolders;
+import org.neo4j.token.api.TokenNotFoundException;
+
+import java.io.IOException;
+
+public class InMemoryCountsStoreImpl implements CountsStore {
+
+ private final GraphStore graphStore;
+ private final TokenHolders tokenHolders;
+
+ public InMemoryCountsStoreImpl(
+ GraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+
+ this.graphStore = graphStore;
+ this.tokenHolders = tokenHolders;
+ }
+
+ @Override
+ public void start(CursorContext cursorContext, MemoryTracker memoryTracker) throws IOException {
+
+ }
+
+ @Override
+ public CountsUpdater updater(long txId, boolean isLast, CursorContext cursorContext) {
+ throw new UnsupportedOperationException("Updates are not supported");
+ }
+
+ @Override
+ public void checkpoint(FileFlushEvent fileFlushEvent, CursorContext cursorContext) {
+
+ }
+
+ @Override
+ public long nodeCount(int labelId, CursorContext cursorContext) {
+ if (labelId == -1) {
+ return graphStore.nodeCount();
+ }
+
+ String nodeLabel;
+ try {
+ nodeLabel = tokenHolders.labelTokens().getTokenById(labelId).name();
+ } catch (TokenNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return graphStore.nodes().nodeCount(NodeLabel.of(nodeLabel));
+ }
+
+ @Override
+ public long relationshipCount(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ // TODO: this is quite wrong
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public boolean consistencyCheck(
+ ReporterFactory reporterFactory,
+ CursorContextFactory cursorContextFactory,
+ int i,
+ ProgressMonitorFactory progressMonitorFactory
+ ) {
+ return true;
+ }
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public void accept(CountsVisitor visitor, CursorContext cursorContext) {
+ tokenHolders.labelTokens().getAllTokens().forEach(labelToken -> {
+ visitor.visitNodeCount(labelToken.id(), nodeCount(labelToken.id(), cursorContext));
+ });
+
+ visitor.visitRelationshipCount(-1, -1, -1, graphStore.relationshipCount());
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryMetaDataProviderImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryMetaDataProviderImpl.java
new file mode 100644
index 00000000000..23790cccb49
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryMetaDataProviderImpl.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.internal.recordstorage.InMemoryLogVersionRepository511;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.TransactionIdSnapshot;
+import org.neo4j.storageengine.api.ClosedTransactionMetadata;
+import org.neo4j.storageengine.api.ExternalStoreId;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.TransactionId;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.UUID;
+
+public class InMemoryMetaDataProviderImpl implements MetadataProvider {
+
+ private final ExternalStoreId externalStoreId;
+ private final InMemoryLogVersionRepository511 logVersionRepository;
+ private final InMemoryTransactionIdStoreImpl transactionIdStore;
+
+ InMemoryMetaDataProviderImpl() {
+ this.logVersionRepository = new InMemoryLogVersionRepository511();
+ this.externalStoreId = new ExternalStoreId(UUID.randomUUID());
+ this.transactionIdStore = new InMemoryTransactionIdStoreImpl();
+ }
+
+ @Override
+ public ExternalStoreId getExternalStoreId() {
+ return this.externalStoreId;
+ }
+
+ @Override
+ public ClosedTransactionMetadata getLastClosedTransaction() {
+ return this.transactionIdStore.getLastClosedTransaction();
+ }
+
+ @Override
+ public void setCurrentLogVersion(long version) {
+ logVersionRepository.setCurrentLogVersion(version);
+ }
+
+ @Override
+ public long incrementAndGetVersion() {
+ return logVersionRepository.incrementAndGetVersion();
+ }
+
+ @Override
+ public void setCheckpointLogVersion(long version) {
+ logVersionRepository.setCheckpointLogVersion(version);
+ }
+
+ @Override
+ public long incrementAndGetCheckpointLogVersion() {
+ return logVersionRepository.incrementAndGetCheckpointLogVersion();
+ }
+
+ @Override
+ public void transactionCommitted(long transactionId, int checksum, long commitTimestamp, long consensusIndex) {
+ transactionIdStore.transactionCommitted(transactionId, checksum, commitTimestamp, consensusIndex);
+ }
+
+ @Override
+ public void setLastCommittedAndClosedTransactionId(
+ long transactionId,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex,
+ long byteOffset,
+ long logVersion
+ ) {
+ transactionIdStore.setLastCommittedAndClosedTransactionId(
+ transactionId,
+ checksum,
+ commitTimestamp,
+ consensusIndex,
+ byteOffset,
+ logVersion
+ );
+ }
+
+ @Override
+ public void transactionClosed(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.transactionIdStore.transactionClosed(
+ transactionId,
+ logVersion,
+ byteOffset,
+ checksum,
+ commitTimestamp,
+ consensusIndex
+ );
+ }
+
+ @Override
+ public void resetLastClosedTransaction(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.transactionIdStore.resetLastClosedTransaction(
+ transactionId,
+ logVersion,
+ byteOffset,
+ checksum,
+ commitTimestamp,
+ consensusIndex
+ );
+ }
+
+ @Override
+ public TransactionIdSnapshot getClosedTransactionSnapshot() {
+ return new TransactionIdSnapshot(this.getLastClosedTransactionId());
+ }
+
+ @Override
+ public void regenerateMetadata(StoreId storeId, UUID externalStoreUUID, CursorContext cursorContext) {
+ }
+
+ @Override
+ public StoreId getStoreId() {
+ return StoreId.UNKNOWN;
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ @Override
+ public long getCurrentLogVersion() {
+ return this.logVersionRepository.getCurrentLogVersion();
+ }
+
+ @Override
+ public long getCheckpointLogVersion() {
+ return this.logVersionRepository.getCheckpointLogVersion();
+ }
+
+ @Override
+ public long nextCommittingTransactionId() {
+ return this.transactionIdStore.nextCommittingTransactionId();
+ }
+
+ @Override
+ public long committingTransactionId() {
+ return this.transactionIdStore.committingTransactionId();
+ }
+
+ @Override
+ public long getLastCommittedTransactionId() {
+ return this.transactionIdStore.getLastCommittedTransactionId();
+ }
+
+ @Override
+ public TransactionId getLastCommittedTransaction() {
+ return this.transactionIdStore.getLastCommittedTransaction();
+ }
+
+ @Override
+ public long getLastClosedTransactionId() {
+ return this.transactionIdStore.getLastClosedTransactionId();
+ }
+
+ @Override
+ public Optional getDatabaseIdUuid(CursorContext cursorTracer) {
+ throw new IllegalStateException("Not supported");
+ }
+
+ @Override
+ public void setDatabaseIdUuid(UUID uuid, CursorContext cursorContext) {
+ throw new IllegalStateException("Not supported");
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodeCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodeCursor.java
new file mode 100644
index 00000000000..5f4bb3cdd0b
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodeCursor.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.api.GraphStore;
+import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
+import org.neo4j.storageengine.api.AllNodeScan;
+import org.neo4j.storageengine.api.Degrees;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.RelationshipSelection;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryNodeCursor extends AbstractInMemoryNodeCursor {
+
+ public InMemoryNodeCursor(GraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public boolean hasLabel() {
+ return hasAtLeastOneLabelForCurrentNode();
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(StoragePropertyCursor propertyCursor, PropertySelection selection) {
+ propertyCursor.initNodeProperties(propertiesReference(), selection);
+ }
+
+ @Override
+ public void properties(StoragePropertyCursor propertyCursor) {
+ properties(propertyCursor, PropertySelection.ALL_PROPERTIES);
+ }
+
+ @Override
+ public boolean supportsFastRelationshipsTo() {
+ return false;
+ }
+
+ @Override
+ public void relationshipsTo(
+ StorageRelationshipTraversalCursor storageRelationshipTraversalCursor,
+ RelationshipSelection relationshipSelection,
+ long neighbourNodeReference
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void degrees(RelationshipSelection selection, Degrees.Mutator mutator) {
+ }
+
+ @Override
+ public boolean scanBatch(AllNodeScan allNodeScan, long sizeHint) {
+ return super.scanBatch(allNodeScan, (int) sizeHint);
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodePropertyCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodePropertyCursor.java
new file mode 100644
index 00000000000..4463339e2b6
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryNodePropertyCursor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryNodePropertyCursor extends AbstractInMemoryNodePropertyCursor {
+
+ public InMemoryNodePropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ reset();
+ setId(((LongReference) reference).id);
+ setPropertySelection(new InMemoryPropertySelectionImpl(selection));
+ }
+
+ @Override
+ public void initRelationshipProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertyCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertyCursor.java
new file mode 100644
index 00000000000..502fda65b2b
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertyCursor.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.AbstractInMemoryPropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StorageNodeCursor;
+import org.neo4j.storageengine.api.StorageRelationshipCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryPropertyCursor extends AbstractInMemoryPropertyCursor {
+
+ public InMemoryPropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryNodePropertyCursor)) {
+ this.delegate = new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryNodePropertyCursor) delegate).initNodeProperties(reference, selection);
+ }
+
+ @Override
+ public void initNodeProperties(StorageNodeCursor nodeCursor, PropertySelection selection) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryNodePropertyCursor)) {
+ this.delegate = new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryNodePropertyCursor) delegate).initNodeProperties(nodeCursor, selection);
+ }
+
+ @Override
+ public void initRelationshipProperties(StorageRelationshipCursor relationshipCursor, PropertySelection selection) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryRelationshipPropertyCursor)) {
+ this.delegate = new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryRelationshipPropertyCursor) delegate).initRelationshipProperties(relationshipCursor, selection);
+ }
+
+ @Override
+ public void initRelationshipProperties(Reference reference, PropertySelection selection, long ownerReference) {
+ if (this.delegate == null || !(this.delegate instanceof InMemoryRelationshipPropertyCursor)) {
+ this.delegate = new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ ((InMemoryRelationshipPropertyCursor) delegate).initRelationshipProperties(reference, selection);
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertySelectionImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertySelectionImpl.java
new file mode 100644
index 00000000000..839a0b7fb34
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryPropertySelectionImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.InMemoryPropertySelection;
+import org.neo4j.storageengine.api.PropertySelection;
+
+public class InMemoryPropertySelectionImpl implements InMemoryPropertySelection {
+
+ private final PropertySelection propertySelection;
+
+ public InMemoryPropertySelectionImpl(PropertySelection propertySelection) {this.propertySelection = propertySelection;}
+
+ @Override
+ public boolean isLimited() {
+ return propertySelection.isLimited();
+ }
+
+ @Override
+ public int numberOfKeys() {
+ return propertySelection.numberOfKeys();
+ }
+
+ @Override
+ public int key(int index) {
+ return propertySelection.key(index);
+ }
+
+ @Override
+ public boolean test(int key) {
+ return propertySelection.test(key);
+ }
+
+ @Override
+ public boolean isKeysOnly() {
+ return propertySelection.isKeysOnly();
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipPropertyCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipPropertyCursor.java
new file mode 100644
index 00000000000..43d155aba61
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipPropertyCursor.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipPropertyCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.gds.storageengine.InMemoryRelationshipCursor;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StorageRelationshipCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipPropertyCursor extends AbstractInMemoryRelationshipPropertyCursor {
+
+ InMemoryRelationshipPropertyCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void initNodeProperties(
+ Reference reference, PropertySelection propertySelection, long ownerReference
+ ) {
+
+ }
+
+ @Override
+ public void initRelationshipProperties(
+ Reference reference, PropertySelection propertySelection, long ownerReference
+ ) {
+ var relationshipId = ((LongReference) reference).id;
+ var relationshipCursor = new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ relationshipCursor.single(relationshipId);
+ relationshipCursor.next();
+ relationshipCursor.properties(this, new InMemoryPropertySelectionImpl(propertySelection));
+ }
+
+ @Override
+ public void initRelationshipProperties(StorageRelationshipCursor relationshipCursor, PropertySelection selection) {
+ var inMemoryRelationshipCursor = (InMemoryRelationshipCursor) relationshipCursor;
+ inMemoryRelationshipCursor.properties(this, selection);
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipScanCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipScanCursor.java
new file mode 100644
index 00000000000..f64ac350f16
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipScanCursor.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
+import org.neo4j.storageengine.api.AllRelationshipsScan;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipScanCursor extends AbstractInMemoryRelationshipScanCursor {
+
+ public InMemoryRelationshipScanCursor(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void single(long reference, long sourceNodeReference, int type, long targetNodeReference) {
+ single(reference);
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(
+ StoragePropertyCursor storagePropertyCursor, PropertySelection propertySelection
+ ) {
+ properties(storagePropertyCursor, new InMemoryPropertySelectionImpl(propertySelection));
+ }
+
+ @Override
+ public boolean scanBatch(AllRelationshipsScan allRelationshipsScan, long sizeHint) {
+ return super.scanBatch(allRelationshipsScan, (int) sizeHint);
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipTraversalCursor.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipTraversalCursor.java
new file mode 100644
index 00000000000..7be8a436257
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryRelationshipTraversalCursor.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.storageengine.api.LongReference;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.Reference;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.token.TokenHolders;
+
+public class InMemoryRelationshipTraversalCursor extends AbstractInMemoryRelationshipTraversalCursor {
+
+ public InMemoryRelationshipTraversalCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ super(graphStore, tokenHolders);
+ }
+
+ @Override
+ public Reference propertiesReference() {
+ return LongReference.longReference(getId());
+ }
+
+ @Override
+ public void properties(
+ StoragePropertyCursor propertyCursor, PropertySelection selection
+ ) {
+ properties(propertyCursor, new InMemoryPropertySelectionImpl(selection));
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java
new file mode 100644
index 00000000000..d08d8b633a3
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineFactory.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.eclipse.collections.api.factory.Sets;
+import org.eclipse.collections.api.set.ImmutableSet;
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.configuration.Config;
+import org.neo4j.consistency.checking.ConsistencyFlags;
+import org.neo4j.consistency.report.ConsistencySummaryStatistics;
+import org.neo4j.dbms.database.readonly.DatabaseReadOnlyChecker;
+import org.neo4j.function.ThrowingSupplier;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineFactoryIdProvider;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.index.internal.gbptree.RecoveryCleanupWorkCollector;
+import org.neo4j.internal.batchimport.AdditionalInitialIds;
+import org.neo4j.internal.batchimport.BatchImporter;
+import org.neo4j.internal.batchimport.Configuration;
+import org.neo4j.internal.batchimport.IncrementalBatchImporter;
+import org.neo4j.internal.batchimport.IndexImporterFactory;
+import org.neo4j.internal.batchimport.Monitor;
+import org.neo4j.internal.batchimport.ReadBehaviour;
+import org.neo4j.internal.batchimport.input.Collector;
+import org.neo4j.internal.batchimport.input.Input;
+import org.neo4j.internal.batchimport.input.LenientStoreInput;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.id.ScanOnOpenReadOnlyIdGeneratorFactory;
+import org.neo4j.internal.recordstorage.InMemoryStorageCommandReaderFactory511;
+import org.neo4j.internal.recordstorage.StoreTokens;
+import org.neo4j.internal.schema.IndexConfigCompleter;
+import org.neo4j.internal.schema.SchemaRule;
+import org.neo4j.internal.schema.SchemaState;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.layout.recordstorage.RecordDatabaseLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.kernel.KernelVersionRepository;
+import org.neo4j.kernel.api.index.IndexProvidersAccess;
+import org.neo4j.kernel.impl.api.index.IndexProviderMap;
+import org.neo4j.kernel.impl.locking.LockManager;
+import org.neo4j.kernel.impl.store.MetaDataStore;
+import org.neo4j.kernel.impl.store.NeoStores;
+import org.neo4j.kernel.impl.store.StoreFactory;
+import org.neo4j.kernel.impl.store.StoreType;
+import org.neo4j.kernel.impl.store.cursor.CachedStoreCursors;
+import org.neo4j.kernel.impl.transaction.log.LogTailLogVersionsMetadata;
+import org.neo4j.kernel.impl.transaction.log.LogTailMetadata;
+import org.neo4j.lock.LockService;
+import org.neo4j.logging.InternalLog;
+import org.neo4j.logging.InternalLogProvider;
+import org.neo4j.logging.NullLogProvider;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.monitoring.DatabaseHealth;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+import org.neo4j.storageengine.api.ConstraintRuleAccessor;
+import org.neo4j.storageengine.api.LogFilesInitializer;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.SchemaRule44;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageFilesState;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.StoreVersionIdentifier;
+import org.neo4j.storageengine.migration.SchemaRuleMigrationAccessExtended;
+import org.neo4j.storageengine.migration.StoreMigrationParticipant;
+import org.neo4j.time.SystemNanoClock;
+import org.neo4j.token.DelegatingTokenHolder;
+import org.neo4j.token.ReadOnlyTokenCreator;
+import org.neo4j.token.TokenHolders;
+import org.neo4j.token.api.NamedToken;
+import org.neo4j.token.api.TokenHolder;
+import org.neo4j.token.api.TokensLoader;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.time.Clock;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.Function;
+
+@ServiceProvider
+public class InMemoryStorageEngineFactory implements StorageEngineFactory {
+
+ static final String IN_MEMORY_STORAGE_ENGINE_NAME = "in-memory-511";
+
+ public InMemoryStorageEngineFactory() {
+ StorageEngineProxyApi.requireNeo4jVersion(Neo4jVersion.V_5_11, StorageEngineFactory.class);
+ }
+
+ @Override
+ public byte id() {
+ return StorageEngineFactoryIdProvider.ID;
+ }
+
+ @Override
+ public boolean storageExists(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout) {
+ return false;
+ }
+
+ @Override
+ public StorageEngine instantiate(
+ FileSystemAbstraction fs,
+ Clock clock,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ TokenHolders tokenHolders,
+ SchemaState schemaState,
+ ConstraintRuleAccessor constraintSemantics,
+ IndexConfigCompleter indexConfigCompleter,
+ LockService lockService,
+ IdGeneratorFactory idGeneratorFactory,
+ DatabaseHealth databaseHealth,
+ InternalLogProvider internalLogProvider,
+ InternalLogProvider userLogProvider,
+ RecoveryCleanupWorkCollector recoveryCleanupWorkCollector,
+ LogTailMetadata logTailMetadata,
+ KernelVersionRepository kernelVersionRepository,
+ MemoryTracker memoryTracker,
+ CursorContextFactory contextFactory,
+ PageCacheTracer pageCacheTracer
+ ) {
+ StoreFactory factory = new StoreFactory(
+ databaseLayout,
+ config,
+ idGeneratorFactory,
+ pageCache,
+ pageCacheTracer,
+ fs,
+ internalLogProvider,
+ contextFactory,
+ false,
+ logTailMetadata
+ );
+
+ factory.openNeoStores(StoreType.LABEL_TOKEN).close();
+
+ return new InMemoryStorageEngineImpl(
+ databaseLayout,
+ tokenHolders
+ );
+ }
+
+ @Override
+ public Optional databaseIdUuid(
+ FileSystemAbstraction fs, DatabaseLayout databaseLayout, PageCache pageCache, CursorContext cursorContext
+ ) {
+ var fieldAccess = MetaDataStore.getFieldAccess(
+ pageCache,
+ RecordDatabaseLayout.convert(databaseLayout).metadataStore(),
+ databaseLayout.getDatabaseName(),
+ cursorContext
+ );
+
+ try {
+ return fieldAccess.readDatabaseUUID();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ @Override
+ public List migrationParticipants(
+ FileSystemAbstraction fileSystemAbstraction,
+ Config config,
+ PageCache pageCache,
+ JobScheduler jobScheduler,
+ LogService logService,
+ MemoryTracker memoryTracker,
+ PageCacheTracer pageCacheTracer,
+ CursorContextFactory cursorContextFactory,
+ boolean b
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public DatabaseLayout databaseLayout(
+ Neo4jLayout neo4jLayout, String databaseName
+ ) {
+ return RecordDatabaseLayout.of(neo4jLayout, databaseName);
+ }
+
+ @Override
+ public DatabaseLayout formatSpecificDatabaseLayout(DatabaseLayout plainLayout) {
+ return databaseLayout(plainLayout.getNeo4jLayout(), plainLayout.getDatabaseName());
+ }
+
+ @SuppressForbidden(reason = "This is the compat layer and we don't really need to go through the proxy")
+ @Override
+ public BatchImporter batchImporter(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ PrintStream printStream,
+ boolean b,
+ AdditionalInitialIds additionalInitialIds,
+ Config config,
+ Monitor monitor,
+ JobScheduler jobScheduler,
+ Collector collector,
+ LogFilesInitializer logFilesInitializer,
+ IndexImporterFactory indexImporterFactory,
+ MemoryTracker memoryTracker,
+ CursorContextFactory cursorContextFactory
+ ) {
+ throw new UnsupportedOperationException("Batch Import into GDS is not supported");
+ }
+
+ @Override
+ public Input asBatchImporterInput(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ MemoryTracker memoryTracker,
+ ReadBehaviour readBehaviour,
+ boolean b,
+ CursorContextFactory cursorContextFactory,
+ LogTailMetadata logTailMetadata
+ ) {
+ NeoStores neoStores = (new StoreFactory(
+ databaseLayout,
+ config,
+ new ScanOnOpenReadOnlyIdGeneratorFactory(),
+ pageCache,
+ pageCacheTracer,
+ fileSystemAbstraction,
+ NullLogProvider.getInstance(),
+ cursorContextFactory,
+ false,
+ logTailMetadata
+ )).openAllNeoStores();
+ return new LenientStoreInput(
+ neoStores,
+ readBehaviour.decorateTokenHolders(this.loadReadOnlyTokens(neoStores, true, cursorContextFactory)),
+ true,
+ cursorContextFactory,
+ readBehaviour
+ );
+ }
+
+ @Override
+ public long optimalAvailableConsistencyCheckerMemory(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache
+ ) {
+ return 0;
+ }
+
+ @Override
+ public String name() {
+ return IN_MEMORY_STORAGE_ENGINE_NAME;
+ }
+
+ @Override
+ public Set supportedFormats(boolean includeFormatsUnderDevelopment) {
+ return Set.of(IN_MEMORY_STORAGE_ENGINE_NAME);
+ }
+
+ @Override
+ public boolean supportedFormat(String format, boolean includeFormatsUnderDevelopment) {
+ return format.equals(IN_MEMORY_STORAGE_ENGINE_NAME);
+ }
+
+ @Override
+ public MetadataProvider transactionMetaDataStore(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ DatabaseReadOnlyChecker readOnlyChecker,
+ CursorContextFactory contextFactory,
+ LogTailLogVersionsMetadata logTailMetadata,
+ PageCacheTracer pageCacheTracer
+ ) throws IOException {
+ return new InMemoryMetaDataProviderImpl();
+ }
+
+ @Override
+ public StoreVersionCheck versionCheck(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ LogService logService,
+ CursorContextFactory cursorContextFactory
+ ) {
+ return new InMemoryVersionCheck();
+ }
+
+ @Override
+ public List loadSchemaRules(
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ boolean b,
+ Function function,
+ CursorContextFactory cursorContextFactory
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public List load44SchemaRules(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContextFactory contextFactory,
+ LogTailLogVersionsMetadata logTailMetadata
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public TokenHolders loadReadOnlyTokens(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ boolean lenient,
+ CursorContextFactory cursorContextFactory
+ ) {
+ StoreFactory factory = new StoreFactory(
+ databaseLayout,
+ config,
+ new ScanOnOpenReadOnlyIdGeneratorFactory(),
+ pageCache,
+ pageCacheTracer,
+ fileSystemAbstraction,
+ NullLogProvider.getInstance(),
+ cursorContextFactory,
+ false,
+ LogTailMetadata.EMPTY_LOG_TAIL
+ );
+ try (
+ NeoStores stores = factory.openNeoStores(
+ StoreType.PROPERTY_KEY_TOKEN, StoreType.PROPERTY_KEY_TOKEN_NAME,
+ StoreType.LABEL_TOKEN, StoreType.LABEL_TOKEN_NAME,
+ StoreType.RELATIONSHIP_TYPE_TOKEN, StoreType.RELATIONSHIP_TYPE_TOKEN_NAME
+ )
+ ) {
+ return loadReadOnlyTokens(stores, lenient, cursorContextFactory);
+ }
+ }
+
+ @Override
+ public SchemaRuleMigrationAccessExtended schemaRuleMigrationAccess(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ PageCacheTracer pageCacheTracer,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContextFactory contextFactory,
+ MemoryTracker memoryTracker
+ ) {
+ // this is used by store copy, which is not supported for GDS storage engine
+ return null;
+ }
+
+ private TokenHolders loadReadOnlyTokens(
+ NeoStores stores,
+ boolean lenient,
+ CursorContextFactory cursorContextFactory
+ ) {
+ try (
+ var cursorContext = cursorContextFactory.create("loadReadOnlyTokens");
+ var storeCursors = new CachedStoreCursors(stores, cursorContext)
+ ) {
+ stores.start( cursorContext );
+ TokensLoader loader = lenient ? StoreTokens.allReadableTokens( stores ) : StoreTokens.allTokens( stores );
+ TokenHolder propertyKeys = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_PROPERTY_KEY );
+ TokenHolder labels = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_LABEL );
+ TokenHolder relationshipTypes = new DelegatingTokenHolder( ReadOnlyTokenCreator.READ_ONLY, TokenHolder.TYPE_RELATIONSHIP_TYPE );
+
+ propertyKeys.setInitialTokens( lenient ? unique( loader.getPropertyKeyTokens( storeCursors ) ) : loader.getPropertyKeyTokens( storeCursors ) );
+ labels.setInitialTokens( lenient ? unique( loader.getLabelTokens( storeCursors ) ) : loader.getLabelTokens( storeCursors ) );
+ relationshipTypes.setInitialTokens(
+ lenient ? unique( loader.getRelationshipTypeTokens( storeCursors ) ) : loader.getRelationshipTypeTokens( storeCursors ) );
+ return new TokenHolders( propertyKeys, labels, relationshipTypes );
+ }
+ catch ( IOException e )
+ {
+ throw new UncheckedIOException( e );
+ }
+ }
+
+ private static List unique( List tokens )
+ {
+ if ( !tokens.isEmpty() )
+ {
+ Set names = new HashSet<>( tokens.size() );
+ int i = 0;
+ while ( i < tokens.size() )
+ {
+ if ( names.add( tokens.get( i ).name() ) )
+ {
+ i++;
+ }
+ else
+ {
+ // Remove the token at the given index, by replacing it with the last token in the list.
+ // This changes the order of elements, but can be done in constant time instead of linear time.
+ int lastIndex = tokens.size() - 1;
+ NamedToken endToken = tokens.remove( lastIndex );
+ if ( i < lastIndex )
+ {
+ tokens.set( i, endToken );
+ }
+ }
+ }
+ }
+ return tokens;
+ }
+
+ @Override
+ public CommandReaderFactory commandReaderFactory() {
+ return InMemoryStorageCommandReaderFactory511.INSTANCE;
+ }
+ @Override
+ public void consistencyCheck(
+ FileSystemAbstraction fileSystem,
+ DatabaseLayout layout,
+ Config config,
+ PageCache pageCache,
+ IndexProviderMap indexProviders,
+ InternalLog reportLog,
+ InternalLog verboseLog,
+ ConsistencySummaryStatistics summary,
+ int numberOfThreads,
+ long maxOffHeapCachingMemory,
+ OutputStream progressOutput,
+ boolean verbose,
+ ConsistencyFlags flags,
+ CursorContextFactory contextFactory,
+ PageCacheTracer pageCacheTracer,
+ LogTailMetadata logTailMetadata
+ ) {
+ // we can do no-op, since our "database" is _always_ consistent
+ }
+
+ @Override
+ public ImmutableSet getStoreOpenOptions(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ DatabaseLayout layout,
+ CursorContextFactory contextFactory
+ ) {
+ // Not sure about this, empty set is returned when the store files are in `little-endian` format
+ // See: `org.neo4j.kernel.impl.store.format.PageCacheOptionsSelector.select`
+ return Sets.immutable.empty();
+ }
+
+ @Override
+ public StoreId retrieveStoreId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ return StoreId.retrieveFromStore(fs, databaseLayout, pageCache, cursorContext);
+ }
+
+
+ @Override
+ public Optional versionInformation(StoreVersionIdentifier storeVersionIdentifier) {
+ return Optional.of(new InMemoryStoreVersion());
+ }
+
+ @Override
+ public void resetMetadata(
+ FileSystemAbstraction fileSystemAbstraction,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ CursorContextFactory cursorContextFactory,
+ PageCacheTracer pageCacheTracer,
+ StoreId storeId,
+ UUID externalStoreId
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IncrementalBatchImporter incrementalBatchImporter(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fileSystemAbstraction,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ PrintStream printStream,
+ boolean b,
+ AdditionalInitialIds additionalInitialIds,
+ ThrowingSupplier throwingSupplier,
+ Config config,
+ Monitor monitor,
+ JobScheduler jobScheduler,
+ Collector collector,
+ LogFilesInitializer logFilesInitializer,
+ IndexImporterFactory indexImporterFactory,
+ MemoryTracker memoryTracker,
+ CursorContextFactory cursorContextFactory,
+ IndexProvidersAccess indexProvidersAccess
+ ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public LockManager createLockManager(Config config, SystemNanoClock systemNanoClock) {
+ return LockManager.NO_LOCKS_LOCK_MANAGER;
+ }
+
+ @Override
+ public List listStorageFiles(
+ FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public StorageFilesState checkStoreFileState(
+ FileSystemAbstraction fs, DatabaseLayout databaseLayout, PageCache pageCache
+ ) {
+ return StorageFilesState.recoveredState();
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineImpl.java
new file mode 100644
index 00000000000..7a80d4e67b0
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageEngineImpl.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.counts.CountsStore;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.gds.compat.TokenManager;
+import org.neo4j.gds.config.GraphProjectConfig;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.gds.core.loading.GraphStoreCatalog;
+import org.neo4j.gds.storageengine.InMemoryDatabaseCreationCatalog;
+import org.neo4j.gds.storageengine.InMemoryTransactionStateVisitor;
+import org.neo4j.internal.diagnostics.DiagnosticsLogger;
+import org.neo4j.internal.recordstorage.InMemoryStorageReader511;
+import org.neo4j.internal.schema.StorageEngineIndexingBehaviour;
+import org.neo4j.io.fs.WritableChannel;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.tracing.DatabaseFlushEvent;
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.kernel.impl.store.stats.StoreEntityCounters;
+import org.neo4j.kernel.lifecycle.Lifecycle;
+import org.neo4j.kernel.lifecycle.LifecycleAdapter;
+import org.neo4j.lock.LockGroup;
+import org.neo4j.lock.LockService;
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.logging.InternalLog;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.storageengine.api.CommandBatchToApply;
+import org.neo4j.storageengine.api.CommandCreationContext;
+import org.neo4j.storageengine.api.CommandStream;
+import org.neo4j.storageengine.api.IndexUpdateListener;
+import org.neo4j.storageengine.api.InternalErrorTracer;
+import org.neo4j.storageengine.api.MetadataProvider;
+import org.neo4j.storageengine.api.StorageCommand;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.storageengine.api.StorageLocks;
+import org.neo4j.storageengine.api.StorageReader;
+import org.neo4j.storageengine.api.StoreFileMetadata;
+import org.neo4j.storageengine.api.StoreId;
+import org.neo4j.storageengine.api.TransactionApplicationMode;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+import org.neo4j.storageengine.api.enrichment.Enrichment;
+import org.neo4j.storageengine.api.enrichment.EnrichmentCommand;
+import org.neo4j.storageengine.api.txstate.ReadableTransactionState;
+import org.neo4j.storageengine.api.txstate.TxStateVisitor;
+import org.neo4j.storageengine.api.txstate.validation.TransactionValidatorFactory;
+import org.neo4j.time.SystemNanoClock;
+import org.neo4j.token.TokenHolders;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
+
+public final class InMemoryStorageEngineImpl implements StorageEngine {
+
+ public static final byte ID = 42;
+ private final MetadataProvider metadataProvider;
+ private final CypherGraphStore graphStore;
+ private final DatabaseLayout databaseLayout;
+ private final InMemoryTransactionStateVisitor txStateVisitor;
+
+ private final CommandCreationContext commandCreationContext;
+
+ private final TokenManager tokenManager;
+ private final InMemoryCountsStoreImpl countsStore;
+
+ private static final StorageEngineIndexingBehaviour INDEXING_BEHAVIOUR = new StorageEngineIndexingBehaviour() {
+ @Override
+ public boolean useNodeIdsInRelationshipTokenIndex() {
+ return false;
+ }
+
+ @Override
+ public boolean requireCoordinationLocks() {
+ return false;
+ }
+
+ @Override
+ public int nodesPerPage() {
+ return 0;
+ }
+
+ @Override
+ public int relationshipsPerPage() {
+ return 0;
+ }
+ };
+
+ InMemoryStorageEngineImpl(
+ DatabaseLayout databaseLayout,
+ TokenHolders tokenHolders
+ ) {
+ this.databaseLayout = databaseLayout;
+ this.graphStore = getGraphStoreFromCatalog(databaseLayout.getDatabaseName());
+ this.txStateVisitor = new InMemoryTransactionStateVisitor(graphStore, tokenHolders);
+ this.commandCreationContext = new InMemoryCommandCreationContextImpl();
+ this.tokenManager = new TokenManager(
+ tokenHolders,
+ InMemoryStorageEngineImpl.this.txStateVisitor,
+ InMemoryStorageEngineImpl.this.graphStore,
+ commandCreationContext
+ );
+ InMemoryStorageEngineImpl.this.graphStore.initialize(tokenHolders);
+ this.countsStore = new InMemoryCountsStoreImpl(graphStore, tokenHolders);
+ this.metadataProvider = new InMemoryMetaDataProviderImpl();
+ }
+
+ private static CypherGraphStore getGraphStoreFromCatalog(String databaseName) {
+ var graphName = InMemoryDatabaseCreationCatalog.getRegisteredDbCreationGraphName(databaseName);
+ return (CypherGraphStore) GraphStoreCatalog.getAllGraphStores()
+ .filter(graphStoreWithUserNameAndConfig -> graphStoreWithUserNameAndConfig
+ .config()
+ .graphName()
+ .equals(graphName))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException(formatWithLocale(
+ "No graph with name `%s` was found in GraphStoreCatalog. Available graph names are %s",
+ graphName,
+ GraphStoreCatalog.getAllGraphStores()
+ .map(GraphStoreCatalog.GraphStoreWithUserNameAndConfig::config)
+ .map(GraphProjectConfig::graphName)
+ .collect(Collectors.toList())
+ )))
+ .graphStore();
+ }
+
+ @Override
+ public StoreEntityCounters storeEntityCounters() {
+ return new StoreEntityCounters() {
+ @Override
+ public long nodes() {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public long relationships() {
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public long properties() {
+ return graphStore.nodePropertyKeys().size() + graphStore.relationshipPropertyKeys().size();
+ }
+
+ @Override
+ public long relationshipTypes() {
+ return graphStore.relationshipTypes().size();
+ }
+
+ @Override
+ public long allNodesCountStore(CursorContext cursorContext) {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public long allRelationshipsCountStore(CursorContext cursorContext) {
+ return graphStore.relationshipCount();
+ }
+ };
+ }
+
+ @Override
+ public StoreCursors createStorageCursors(CursorContext initialContext) {
+ return StoreCursors.NULL;
+ }
+
+ @Override
+ public StorageLocks createStorageLocks(ResourceLocker locker) {
+ return new InMemoryStorageLocksImpl(locker);
+ }
+
+ @Override
+ public List createCommands(
+ ReadableTransactionState state,
+ StorageReader storageReader,
+ CommandCreationContext creationContext,
+ LockTracer lockTracer,
+ TxStateVisitor.Decorator additionalTxStateVisitor,
+ CursorContext cursorContext,
+ StoreCursors storeCursors,
+ MemoryTracker memoryTracker
+ ) throws KernelException {
+ state.accept(txStateVisitor);
+ return List.of();
+ }
+
+ @Override
+ public void dumpDiagnostics(InternalLog internalLog, DiagnosticsLogger diagnosticsLogger) {
+ }
+
+ @Override
+ public List createUpgradeCommands(
+ KernelVersion versionToUpgradeFrom,
+ KernelVersion versionToUpgradeTo
+ ) {
+ return List.of();
+ }
+
+ @Override
+ public StoreId retrieveStoreId() {
+ return metadataProvider.getStoreId();
+ }
+
+ @Override
+ public StorageEngineIndexingBehaviour indexingBehaviour() {
+ return INDEXING_BEHAVIOUR;
+ }
+
+ @Override
+ public StorageReader newReader() {
+ return new InMemoryStorageReader511(graphStore, tokenManager.tokenHolders(), countsStore);
+ }
+
+ @Override
+ public void addIndexUpdateListener(IndexUpdateListener listener) {
+
+ }
+
+ @Override
+ public void apply(CommandBatchToApply batch, TransactionApplicationMode mode) {
+ }
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void stop() {
+ shutdown();
+ }
+
+ @Override
+ public void shutdown() {
+ InMemoryDatabaseCreationCatalog.removeDatabaseEntry(databaseLayout.getDatabaseName());
+ }
+
+ @Override
+ public void listStorageFiles(
+ Collection atomic, Collection replayable
+ ) {
+
+ }
+
+ @Override
+ public Lifecycle schemaAndTokensLifecycle() {
+ return new LifecycleAdapter() {
+ @Override
+ public void init() {
+
+ }
+ };
+ }
+
+ @Override
+ public CountsStore countsAccessor() {
+ return countsStore;
+ }
+
+ @Override
+ public MetadataProvider metadataProvider() {
+ return metadataProvider;
+ }
+
+ @Override
+ public String name() {
+ return "gds in-memory storage engine";
+ }
+
+ @Override
+ public byte id() {
+ return ID;
+ }
+
+ @Override
+ public CommandCreationContext newCommandCreationContext(boolean multiVersioned) {
+ return commandCreationContext;
+ }
+
+ @Override
+ public TransactionValidatorFactory createTransactionValidatorFactory(
+ StorageEngineFactory storageEngineFactory,
+ Config config,
+ SystemNanoClock systemNanoClock
+ ) {
+ return TransactionValidatorFactory.EMPTY_VALIDATOR_FACTORY;
+ }
+
+ @Override
+ public void lockRecoveryCommands(
+ CommandStream commands, LockService lockService, LockGroup lockGroup, TransactionApplicationMode mode
+ ) {
+
+ }
+
+ @Override
+ public void rollback(ReadableTransactionState txState, CursorContext cursorContext) {
+ // rollback is not supported but it is also called when we fail for something else
+ // that we do not support, such as removing node properties
+ // TODO: do we want to inspect the txState to infer if rollback was called explicitly or not?
+ }
+
+ @Override
+ public void checkpoint(DatabaseFlushEvent flushEvent, CursorContext cursorContext) {
+ // checkpoint is not supported but it is also called when we fail for something else
+ // that we do not support, such as removing node properties
+ }
+
+ @Override
+ public void preAllocateStoreFilesForCommands(CommandBatchToApply batch, TransactionApplicationMode mode) {
+ // GDS has its own mechanism of memory allocation, so we don't need this
+ }
+
+ @Override
+ public EnrichmentCommand createEnrichmentCommand(KernelVersion kernelVersion, Enrichment enrichment) {
+ return new EnrichmentCommand() {
+
+ @Override
+ public Enrichment enrichment() {
+ return null;
+ }
+
+ @Override
+ public void serialize(WritableChannel channel) {
+
+ }
+
+ @Override
+ public KernelVersion kernelVersion() {
+ return kernelVersion;
+ }
+ };
+ }
+
+ @Override
+ public InternalErrorTracer internalErrorTracer() {
+ return InternalErrorTracer.NO_TRACER;
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageLocksImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageLocksImpl.java
new file mode 100644
index 00000000000..a7ac028ce8f
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStorageLocksImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.lock.LockTracer;
+import org.neo4j.lock.ResourceLocker;
+import org.neo4j.storageengine.api.StorageLocks;
+import org.neo4j.storageengine.api.txstate.ReadableTransactionState;
+
+public class InMemoryStorageLocksImpl implements StorageLocks {
+
+ InMemoryStorageLocksImpl(ResourceLocker locker) {}
+
+ @Override
+ public void acquireExclusiveNodeLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseExclusiveNodeLock(long... ids) {}
+
+ @Override
+ public void acquireSharedNodeLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseSharedNodeLock(long... ids) {}
+
+ @Override
+ public void acquireExclusiveRelationshipLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseExclusiveRelationshipLock(long... ids) {}
+
+ @Override
+ public void acquireSharedRelationshipLock(LockTracer lockTracer, long... ids) {}
+
+ @Override
+ public void releaseSharedRelationshipLock(long... ids) {}
+
+ @Override
+ public void acquireRelationshipCreationLock(
+ LockTracer lockTracer,
+ long sourceNode,
+ long targetNode,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ }
+
+ @Override
+ public void acquireRelationshipDeletionLock(
+ LockTracer lockTracer,
+ long sourceNode,
+ long targetNode,
+ long relationship,
+ boolean relationshipAddedInTx,
+ boolean sourceNodeAddedInTx,
+ boolean targetNodeAddedInTx
+ ) {
+ }
+
+ @Override
+ public void acquireNodeDeletionLock(
+ ReadableTransactionState readableTransactionState,
+ LockTracer lockTracer,
+ long node
+ ) {}
+
+ @Override
+ public void acquireNodeLabelChangeLock(LockTracer lockTracer, long node, int labelId) {}
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStoreVersion.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStoreVersion.java
new file mode 100644
index 00000000000..946e7579069
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryStoreVersion.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.storageengine.api.StoreVersion;
+import org.neo4j.storageengine.api.format.Capability;
+import org.neo4j.storageengine.api.format.CapabilityType;
+
+import java.util.Optional;
+
+public class InMemoryStoreVersion implements StoreVersion {
+
+ public static final String STORE_VERSION = "gds-experimental";
+
+ @Override
+ public String getStoreVersionUserString() {
+ return "Unknown";
+ }
+
+ @Override
+ public Optional successorStoreVersion(Config config) {
+ return Optional.empty();
+ }
+
+ @Override
+ public String formatName() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public boolean onlyForMigration() {
+ return false;
+ }
+
+ @Override
+ public boolean hasCapability(Capability capability) {
+ return false;
+ }
+
+ @Override
+ public boolean hasCompatibleCapabilities(
+ StoreVersion otherVersion, CapabilityType type
+ ) {
+ return false;
+ }
+
+ @Override
+ public String introductionNeo4jVersion() {
+ return "foo";
+ }
+
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryTransactionIdStoreImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryTransactionIdStoreImpl.java
new file mode 100644
index 00000000000..c95a6524be9
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryTransactionIdStoreImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.internal.recordstorage.AbstractTransactionIdStore;
+import org.neo4j.io.pagecache.context.TransactionIdSnapshot;
+import org.neo4j.kernel.impl.transaction.log.LogPosition;
+import org.neo4j.storageengine.api.ClosedTransactionMetadata;
+import org.neo4j.storageengine.api.TransactionId;
+import org.neo4j.storageengine.api.TransactionIdStore;
+
+public class InMemoryTransactionIdStoreImpl extends AbstractTransactionIdStore {
+
+ @Override
+ protected void initLastCommittedAndClosedTransactionId(
+ long previouslyCommittedTxId,
+ int checksum,
+ long previouslyCommittedTxCommitTimestamp,
+ long previouslyCommittedTxLogByteOffset,
+ long previouslyCommittedTxLogVersion
+ ) {
+ this.setLastCommittedAndClosedTransactionId(
+ previouslyCommittedTxId,
+ checksum,
+ previouslyCommittedTxCommitTimestamp,
+ TransactionIdStore.UNKNOWN_CONSENSUS_INDEX,
+ previouslyCommittedTxLogByteOffset,
+ previouslyCommittedTxLogVersion
+ );
+ }
+
+ @Override
+ public ClosedTransactionMetadata getLastClosedTransaction() {
+ long[] metaData = this.closedTransactionId.get();
+ return new ClosedTransactionMetadata(
+ metaData[0],
+ new LogPosition(metaData[1], metaData[2]),
+ (int) metaData[3],
+ metaData[4],
+ metaData[5]
+ );
+ }
+
+ @Override
+ public TransactionIdSnapshot getClosedTransactionSnapshot() {
+ return new TransactionIdSnapshot(this.getLastClosedTransactionId());
+ }
+
+ @Override
+ protected TransactionId transactionId(long transactionId, int checksum, long commitTimestamp) {
+ return new TransactionId(transactionId, checksum, commitTimestamp, TransactionIdStore.UNKNOWN_CONSENSUS_INDEX);
+ }
+
+ @Override
+ public void transactionCommitted(long transactionId, int checksum, long commitTimestamp, long consensusIndex) {
+
+ }
+
+ @Override
+ public void setLastCommittedAndClosedTransactionId(
+ long transactionId,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex,
+ long byteOffset,
+ long logVersion
+ ) {
+
+ }
+
+ @Override
+ public void transactionClosed(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.closedTransactionId.offer(
+ transactionId,
+ new long[]{logVersion, byteOffset, checksum, commitTimestamp, consensusIndex}
+ );
+ }
+
+ @Override
+ public void resetLastClosedTransaction(
+ long transactionId,
+ long logVersion,
+ long byteOffset,
+ int checksum,
+ long commitTimestamp,
+ long consensusIndex
+ ) {
+ this.closedTransactionId.set(
+ transactionId,
+ new long[]{logVersion, byteOffset, checksum, commitTimestamp, consensusIndex}
+ );
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryVersionCheck.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryVersionCheck.java
new file mode 100644
index 00000000000..8cb999f8c76
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/InMemoryVersionCheck.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.kernel.impl.store.format.FormatFamily;
+import org.neo4j.storageengine.api.StoreVersionCheck;
+import org.neo4j.storageengine.api.StoreVersionIdentifier;
+
+import static org.neo4j.gds.compat._511.InMemoryStoreVersion.STORE_VERSION;
+
+public class InMemoryVersionCheck implements StoreVersionCheck {
+
+ private static final StoreVersionIdentifier STORE_IDENTIFIER = new StoreVersionIdentifier(
+ STORE_VERSION,
+ FormatFamily.STANDARD.name(),
+ 0,
+ 0
+ );
+
+ @Override
+ public boolean isCurrentStoreVersionFullySupported(CursorContext cursorContext) {
+ return true;
+ }
+
+ @Override
+ public MigrationCheckResult getAndCheckMigrationTargetVersion(String formatFamily, CursorContext cursorContext) {
+ return new StoreVersionCheck.MigrationCheckResult(MigrationOutcome.NO_OP, STORE_IDENTIFIER, null, null);
+ }
+
+ @Override
+ public UpgradeCheckResult getAndCheckUpgradeTargetVersion(CursorContext cursorContext) {
+ return new StoreVersionCheck.UpgradeCheckResult(UpgradeOutcome.NO_OP, STORE_IDENTIFIER, null, null);
+ }
+
+ @Override
+ public String getIntroductionVersionFromVersion(StoreVersionIdentifier storeVersionIdentifier) {
+ return STORE_VERSION;
+ }
+
+ public StoreVersionIdentifier findLatestVersion(String s) {
+ return STORE_IDENTIFIER;
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 00000000000..687468d4e45
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.compat.StorageEngineProxyFactory;
+
+@ServiceProvider
+public class StorageEngineProxyFactoryImpl implements StorageEngineProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_11;
+ }
+
+ @Override
+ public StorageEngineProxyApi load() {
+ return new StorageEngineProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.11";
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyImpl.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyImpl.java
new file mode 100644
index 00000000000..d2688f8a37a
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_511/StorageEngineProxyImpl.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._511;
+
+import org.neo4j.common.Edition;
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.GraphDatabaseInternalSettings;
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.gds.compat.AbstractInMemoryNodeCursor;
+import org.neo4j.gds.compat.AbstractInMemoryNodePropertyCursor;
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipPropertyCursor;
+import org.neo4j.gds.compat.AbstractInMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat.StorageEngineProxyApi;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.internal.recordstorage.AbstractInMemoryRelationshipScanCursor;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.RelationshipSelection;
+import org.neo4j.storageengine.api.StorageEngine;
+import org.neo4j.storageengine.api.StorageEntityCursor;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.token.TokenHolders;
+
+import static org.neo4j.configuration.GraphDatabaseSettings.db_format;
+
+public class StorageEngineProxyImpl implements StorageEngineProxyApi {
+
+ @Override
+ public void initRelationshipTraversalCursorForRelType(
+ StorageRelationshipTraversalCursor cursor,
+ long sourceNodeId,
+ int relTypeToken
+ ) {
+ var relationshipSelection = RelationshipSelection.selection(
+ relTypeToken,
+ Direction.OUTGOING
+ );
+ cursor.init(sourceNodeId, -1, relationshipSelection);
+ }
+
+ @Override
+ public StorageEngine createInMemoryStorageEngine(DatabaseLayout databaseLayout, TokenHolders tokenHolders) {
+ return new InMemoryStorageEngineImpl(databaseLayout, tokenHolders);
+ }
+
+ @Override
+ public void createInMemoryDatabase(
+ DatabaseManagementService dbms,
+ String dbName,
+ Config config
+ ) {
+ config.set(db_format, InMemoryStorageEngineFactory.IN_MEMORY_STORAGE_ENGINE_NAME);
+ dbms.createDatabase(dbName, config);
+ }
+
+ @Override
+ public GraphDatabaseService startAndGetInMemoryDatabase(DatabaseManagementService dbms, String dbName) {
+ dbms.startDatabase(dbName);
+ return dbms.database(dbName);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setSkipDefaultIndexesOnCreationSetting(GdsDatabaseManagementServiceBuilder dbmsBuilder) {
+ return dbmsBuilder.setConfig(GraphDatabaseInternalSettings.skip_default_indexes_on_creation, true);
+ }
+
+ @Override
+ public AbstractInMemoryNodeCursor inMemoryNodeCursor(CypherGraphStore graphStore, TokenHolders tokenHolders) {
+ return new InMemoryNodeCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryNodePropertyCursor inMemoryNodePropertyCursor(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders
+ ) {
+ return new InMemoryNodePropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipTraversalCursor inMemoryRelationshipTraversalCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipTraversalCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipScanCursor inMemoryRelationshipScanCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public AbstractInMemoryRelationshipPropertyCursor inMemoryRelationshipPropertyCursor(
+ CypherGraphStore graphStore, TokenHolders tokenHolders
+ ) {
+ return new InMemoryRelationshipPropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public void properties(
+ StorageEntityCursor storageCursor, StoragePropertyCursor propertyCursor, int[] propertySelection
+ ) {
+ PropertySelection selection;
+ if (propertySelection.length == 0) {
+ selection = PropertySelection.ALL_PROPERTIES;
+ } else {
+ selection = PropertySelection.selection(propertySelection);
+ }
+ storageCursor.properties(propertyCursor, selection);
+ }
+
+ @Override
+ public Edition dbmsEdition(GraphDatabaseService databaseService) {
+ return GraphDatabaseApiProxy.dbmsInfo(databaseService).edition;
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository511.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository511.java
new file mode 100644
index 00000000000..542a9239cdb
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository511.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.neo4j.storageengine.api.LogVersionRepository;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class InMemoryLogVersionRepository511 implements LogVersionRepository {
+
+ private final AtomicLong logVersion;
+ private final AtomicLong checkpointLogVersion;
+
+ public InMemoryLogVersionRepository511() {
+ this(0, 0);
+ }
+
+ private InMemoryLogVersionRepository511(long initialLogVersion, long initialCheckpointLogVersion) {
+ this.logVersion = new AtomicLong();
+ this.checkpointLogVersion = new AtomicLong();
+ this.logVersion.set(initialLogVersion);
+ this.checkpointLogVersion.set(initialCheckpointLogVersion);
+ }
+
+ @Override
+ public void setCurrentLogVersion(long version) {
+ this.logVersion.set(version);
+ }
+
+ @Override
+ public long incrementAndGetVersion() {
+ return this.logVersion.incrementAndGet();
+ }
+
+ @Override
+ public void setCheckpointLogVersion(long version) {
+ this.checkpointLogVersion.set(version);
+ }
+
+ @Override
+ public long incrementAndGetCheckpointLogVersion() {
+ return this.checkpointLogVersion.incrementAndGet();
+ }
+
+ @Override
+ public long getCurrentLogVersion() {
+ return this.logVersion.get();
+ }
+
+ @Override
+ public long getCheckpointLogVersion() {
+ return this.checkpointLogVersion.get();
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory511.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory511.java
new file mode 100644
index 00000000000..004ffea98d4
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory511.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.neo4j.kernel.KernelVersion;
+import org.neo4j.storageengine.api.CommandReader;
+import org.neo4j.storageengine.api.CommandReaderFactory;
+
+public class InMemoryStorageCommandReaderFactory511 implements CommandReaderFactory {
+
+ public static final CommandReaderFactory INSTANCE = new InMemoryStorageCommandReaderFactory511();
+
+ @Override
+ public CommandReader get(KernelVersion kernelVersion) {
+ switch (kernelVersion) {
+ case V4_2:
+ return LogCommandSerializationV4_2.INSTANCE;
+ case V4_3_D4:
+ return LogCommandSerializationV4_3_D3.INSTANCE;
+ case V5_0:
+ return LogCommandSerializationV5_0.INSTANCE;
+ default:
+ throw new IllegalArgumentException("Unsupported kernel version " + kernelVersion);
+ }
+ }
+}
diff --git a/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader511.java b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader511.java
new file mode 100644
index 00000000000..9ba49899c70
--- /dev/null
+++ b/compatibility/5.11/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader511.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.internal.recordstorage;
+
+import org.eclipse.collections.api.set.primitive.IntSet;
+import org.eclipse.collections.impl.set.immutable.primitive.ImmutableIntSetFactoryImpl;
+import org.neo4j.common.EntityType;
+import org.neo4j.common.TokenNameLookup;
+import org.neo4j.counts.CountsStore;
+import org.neo4j.gds.compat._511.InMemoryNodeCursor;
+import org.neo4j.gds.compat._511.InMemoryPropertyCursor;
+import org.neo4j.gds.compat._511.InMemoryRelationshipScanCursor;
+import org.neo4j.gds.compat._511.InMemoryRelationshipTraversalCursor;
+import org.neo4j.gds.core.cypher.CypherGraphStore;
+import org.neo4j.internal.schema.ConstraintDescriptor;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexType;
+import org.neo4j.internal.schema.SchemaDescriptor;
+import org.neo4j.internal.schema.constraints.IndexBackedConstraintDescriptor;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.memory.MemoryTracker;
+import org.neo4j.storageengine.api.AllNodeScan;
+import org.neo4j.storageengine.api.AllRelationshipsScan;
+import org.neo4j.storageengine.api.StorageNodeCursor;
+import org.neo4j.storageengine.api.StoragePropertyCursor;
+import org.neo4j.storageengine.api.StorageReader;
+import org.neo4j.storageengine.api.StorageRelationshipScanCursor;
+import org.neo4j.storageengine.api.StorageRelationshipTraversalCursor;
+import org.neo4j.storageengine.api.StorageSchemaReader;
+import org.neo4j.storageengine.api.cursor.StoreCursors;
+import org.neo4j.token.TokenHolders;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+public class InMemoryStorageReader511 implements StorageReader {
+
+ protected final CypherGraphStore graphStore;
+ protected final TokenHolders tokenHolders;
+ protected final CountsStore counts;
+ private final Map, Object> dependantState;
+ private boolean closed;
+
+ public InMemoryStorageReader511(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders,
+ CountsStore counts
+ ) {
+ this.graphStore = graphStore;
+
+ this.tokenHolders = tokenHolders;
+ this.counts = counts;
+ this.dependantState = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] changedLabels,
+ long[] unchangedLabels,
+ int[] propertyKeyIds,
+ boolean propertyKeyListIsComplete,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public long relationshipsGetCount(CursorContext cursorTracer) {
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public boolean nodeExists(long id, StoreCursors storeCursors) {
+ var originalId = graphStore.nodes().toOriginalNodeId(id);
+ return graphStore.nodes().containsOriginalId(originalId);
+ }
+
+ @Override
+ public boolean relationshipExists(long id, StoreCursors storeCursors) {
+ return true;
+ }
+
+ @Override
+ public StorageNodeCursor allocateNodeCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryNodeCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StoragePropertyCursor allocatePropertyCursor(
+ CursorContext cursorContext, StoreCursors storeCursors, MemoryTracker memoryTracker
+ ) {
+ return new InMemoryPropertyCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StorageRelationshipTraversalCursor allocateRelationshipTraversalCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryRelationshipTraversalCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public StorageRelationshipScanCursor allocateRelationshipScanCursor(
+ CursorContext cursorContext, StoreCursors storeCursors
+ ) {
+ return new InMemoryRelationshipScanCursor(graphStore, tokenHolders);
+ }
+
+ @Override
+ public IndexDescriptor indexGetForSchemaAndType(
+ SchemaDescriptor descriptor, IndexType type
+ ) {
+ return null;
+ }
+
+ @Override
+ public AllRelationshipsScan allRelationshipScan() {
+ return new AbstractInMemoryAllRelationshipScan() {
+ @Override
+ boolean scanRange(AbstractInMemoryRelationshipScanCursor cursor, long start, long stopInclusive) {
+ return cursor.scanRange(start, stopInclusive);
+ }
+
+ @Override
+ public boolean scanBatch(long sizeHint, AbstractInMemoryRelationshipScanCursor cursor) {
+ return super.scanBatch(sizeHint, cursor);
+ }
+ };
+ }
+
+ @Override
+ public Iterator indexGetForSchema(SchemaDescriptor descriptor) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator indexesGetForLabel(int labelId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator indexesGetForRelationshipType(int relationshipType) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public IndexDescriptor indexGetForName(String name) {
+ return null;
+ }
+
+ @Override
+ public ConstraintDescriptor constraintGetForName(String name) {
+ return null;
+ }
+
+ @Override
+ public boolean indexExists(IndexDescriptor index) {
+ return false;
+ }
+
+ @Override
+ public Iterator indexesGetAll() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Collection valueIndexesGetRelated(
+ long[] tokens, int propertyKeyId, EntityType entityType
+ ) {
+ return valueIndexesGetRelated(tokens, new int[]{propertyKeyId}, entityType);
+ }
+
+ @Override
+ public Collection valueIndexesGetRelated(
+ long[] tokens, int[] propertyKeyIds, EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] labels,
+ int propertyKeyId,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ long[] tokens,
+ int[] propertyKeyIds,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean hasRelatedSchema(long[] labels, int propertyKey, EntityType entityType) {
+ return false;
+ }
+
+ @Override
+ public boolean hasRelatedSchema(int label, EntityType entityType) {
+ return false;
+ }
+
+ @Override
+ public Iterator constraintsGetForSchema(SchemaDescriptor descriptor) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public boolean constraintExists(ConstraintDescriptor descriptor) {
+ return false;
+ }
+
+ @Override
+ public Iterator constraintsGetForLabel(int labelId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator constraintsGetForRelationshipType(int typeId) {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public Iterator constraintsGetAll() {
+ return Collections.emptyIterator();
+ }
+
+ @Override
+ public IntSet constraintsGetPropertyTokensForLogicalKey(int token, EntityType entityType) {
+ return ImmutableIntSetFactoryImpl.INSTANCE.empty();
+ }
+
+ @Override
+ public Long indexGetOwningUniquenessConstraintId(IndexDescriptor index) {
+ return null;
+ }
+
+ @Override
+ public long countsForNode(int labelId, CursorContext cursorContext) {
+ return counts.nodeCount(labelId, cursorContext);
+ }
+
+ @Override
+ public long countsForRelationship(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ return counts.relationshipCount(startLabelId, typeId, endLabelId, cursorContext);
+ }
+
+ @Override
+ public long nodesGetCount(CursorContext cursorContext) {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public int labelCount() {
+ return graphStore.nodes().availableNodeLabels().size();
+ }
+
+ @Override
+ public int propertyKeyCount() {
+ int nodePropertyCount = graphStore
+ .schema()
+ .nodeSchema()
+ .unionProperties()
+ .size();
+ int relPropertyCount = graphStore
+ .schema()
+ .relationshipSchema()
+ .unionProperties()
+ .size();
+
+ return nodePropertyCount + relPropertyCount;
+ }
+
+ @Override
+ public int relationshipTypeCount() {
+ return graphStore.schema().relationshipSchema().entries().size();
+ }
+
+ @Override
+ public T getOrCreateSchemaDependantState(Class type, Function factory) {
+ return type.cast(dependantState.computeIfAbsent(type, key -> factory.apply(this)));
+ }
+
+ @Override
+ public AllNodeScan allNodeScan() {
+ return new InMemoryNodeScan();
+ }
+
+ @Override
+ public void close() {
+ assert !closed;
+ closed = true;
+ }
+
+ @Override
+ public StorageSchemaReader schemaSnapshot() {
+ return this;
+ }
+
+ @Override
+ public TokenNameLookup tokenNameLookup() {
+ return tokenHolders;
+ }
+
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/build.gradle b/compatibility/5.12/neo4j-kernel-adapter/build.gradle
new file mode 100644
index 00000000000..498b905b8ba
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/build.gradle
@@ -0,0 +1,65 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Neo4j Kernel Adapter 5.12'
+
+group = 'org.neo4j.gds'
+
+// for all 5.x versions
+if (ver.'neo4j'.startsWith('5.')) {
+ sourceSets {
+ main {
+ java {
+ srcDirs = ['src/main/java17']
+ }
+ }
+ }
+
+ dependencies {
+ annotationProcessor project(':annotations')
+ annotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.12'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+ compileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ compileOnly group: 'org.neo4j', name: 'annotations', version: neos.'5.12'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.12'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.12'
+ compileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.12'
+
+ implementation project(':neo4j-kernel-adapter-api')
+ }
+} else {
+ multiRelease {
+ targetVersions 11, 17
+ }
+
+ if (!project.hasProperty('no-forbidden-apis')) {
+ forbiddenApisJava17 {
+ exclude('**')
+ }
+ }
+
+ dependencies {
+ annotationProcessor group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ compileOnly project(':annotations')
+ compileOnly group: 'org.neo4j', name: 'annotations', version: ver.'neo4j'
+
+ implementation project(':neo4j-kernel-adapter-api')
+
+ java17AnnotationProcessor project(':annotations')
+ java17AnnotationProcessor group: 'org.immutables', name: 'value', version: ver.'immutables'
+ java17AnnotationProcessor group: 'org.neo4j', name: 'annotations', version: neos.'5.12'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.12'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.12'
+ java17CompileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.12'
+ java17CompileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+
+ java17Implementation project(':neo4j-kernel-adapter-api')
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..3c34c8cd8d5
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ throw new UnsupportedOperationException("5.12 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.12 (placeholder)";
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..2c165303d66
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return false;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ throw new UnsupportedOperationException("5.12 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.12 (placeholder)";
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/BoltTransactionRunnerImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/BoltTransactionRunnerImpl.java
new file mode 100644
index 00000000000..6148b17ef9d
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/BoltTransactionRunnerImpl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.bolt.dbapi.BoltGraphDatabaseServiceSPI;
+import org.neo4j.bolt.dbapi.BoltTransaction;
+import org.neo4j.bolt.protocol.common.message.AccessMode;
+import org.neo4j.bolt.protocol.common.message.request.connection.RoutingContext;
+import org.neo4j.bolt.tx.statement.StatementQuerySubscriber;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.gds.compat.BoltQuerySubscriber;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.graphdb.QueryStatistics;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.QueryExecutionKernelException;
+import org.neo4j.values.virtual.MapValue;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+public class BoltTransactionRunnerImpl extends BoltTransactionRunner {
+
+ @Override
+ protected BoltQuerySubscriber boltQuerySubscriber() {
+ var subscriber = new StatementQuerySubscriber();
+ return new BoltQuerySubscriber<>() {
+ @Override
+ public void assertSucceeded() throws KernelException {
+ subscriber.assertSuccess();
+ }
+
+ @Override
+ public QueryStatistics queryStatistics() {
+ return subscriber.getStatistics();
+ }
+
+ @Override
+ public StatementQuerySubscriber innerSubscriber() {
+ return subscriber;
+ }
+ };
+ }
+
+ @Override
+ protected void executeQuery(
+ BoltTransaction boltTransaction,
+ String query,
+ MapValue parameters,
+ StatementQuerySubscriber querySubscriber
+ ) throws QueryExecutionKernelException {
+ boltTransaction.executeQuery(query, parameters, true, querySubscriber);
+ }
+
+ @Override
+ protected BoltTransaction beginBoltWriteTransaction(
+ BoltGraphDatabaseServiceSPI fabricDb,
+ LoginContext loginContext,
+ KernelTransaction.Type kernelTransactionType,
+ ClientConnectionInfo clientConnectionInfo,
+ List bookmarks,
+ Duration txTimeout,
+ Map txMetadata
+ ) {
+ return fabricDb.beginTransaction(
+ kernelTransactionType,
+ loginContext,
+ clientConnectionInfo,
+ bookmarks,
+ txTimeout,
+ AccessMode.WRITE,
+ txMetadata,
+ new RoutingContext(true, Map.of()),
+ QueryExecutionConfiguration.DEFAULT_CONFIG
+ );
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableProcedureImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableProcedureImpl.java
new file mode 100644
index 00000000000..c940486e6d2
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableProcedureImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.collection.RawIterator;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.kernel.api.ResourceMonitor;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableProcedureImpl implements CallableProcedure {
+ private final CompatCallableProcedure procedure;
+
+ CallableProcedureImpl(CompatCallableProcedure procedure) {
+ this.procedure = procedure;
+ }
+
+ @Override
+ public ProcedureSignature signature() {
+ return this.procedure.signature();
+ }
+
+ @Override
+ public RawIterator apply(
+ Context ctx,
+ AnyValue[] input,
+ ResourceMonitor resourceMonitor
+ ) throws ProcedureException {
+ return this.procedure.apply(ctx, input);
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableUserAggregationFunctionImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableUserAggregationFunctionImpl.java
new file mode 100644
index 00000000000..68e4cd838a1
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CallableUserAggregationFunctionImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompatUserAggregator;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.UserAggregationReducer;
+import org.neo4j.internal.kernel.api.procs.UserAggregationUpdater;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.values.AnyValue;
+
+@SuppressForbidden(reason = "This is the compat API")
+public final class CallableUserAggregationFunctionImpl implements CallableUserAggregationFunction {
+ private final CompatUserAggregationFunction function;
+
+ CallableUserAggregationFunctionImpl(CompatUserAggregationFunction function) {
+ this.function = function;
+ }
+
+ @Override
+ public UserFunctionSignature signature() {
+ return this.function.signature();
+ }
+
+ @Override
+ public UserAggregationReducer createReducer(Context ctx) throws ProcedureException {
+ return new UserAggregatorImpl(this.function.create(ctx));
+ }
+
+ private static final class UserAggregatorImpl implements UserAggregationReducer, UserAggregationUpdater {
+ private final CompatUserAggregator aggregator;
+
+ private UserAggregatorImpl(CompatUserAggregator aggregator) {
+ this.aggregator = aggregator;
+ }
+
+ @Override
+ public UserAggregationUpdater newUpdater() {
+ return this;
+ }
+
+ @Override
+ public void update(AnyValue[] input) throws ProcedureException {
+ this.aggregator.update(input);
+ }
+
+ @Override
+ public void applyUpdates() {
+ }
+
+ @Override
+ public AnyValue result() throws ProcedureException {
+ return this.aggregator.result();
+ }
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatAccessModeImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatAccessModeImpl.java
new file mode 100644
index 00000000000..f11614a613b
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatAccessModeImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.CompatAccessMode;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.internal.kernel.api.RelTypeSupplier;
+import org.neo4j.internal.kernel.api.TokenSet;
+
+import java.util.function.Supplier;
+
+public class CompatAccessModeImpl extends CompatAccessMode {
+
+ CompatAccessModeImpl(CustomAccessMode custom) {
+ super(custom);
+ }
+
+ @Override
+ public boolean allowsReadNodeProperty(Supplier labels, int propertyKey) {
+ return custom.allowsReadNodeProperty(propertyKey);
+ }
+
+ @Override
+ public boolean allowsReadRelationshipProperty(RelTypeSupplier relType, int propertyKey) {
+ return custom.allowsReadRelationshipProperty(propertyKey);
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatGraphDatabaseAPIImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatGraphDatabaseAPIImpl.java
new file mode 100644
index 00000000000..f4995ac8ba4
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatGraphDatabaseAPIImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.security.LoginContext;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.exceptions.Status;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.coreapi.TransactionExceptionMapper;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+final class CompatGraphDatabaseAPIImpl extends GdsGraphDatabaseAPI {
+
+ CompatGraphDatabaseAPIImpl(DatabaseManagementService dbms) {
+ super(dbms);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return api.isAvailable();
+ }
+
+ @Override
+ public TopologyGraphDbmsModel.HostedOnMode mode() {
+ // NOTE: This means we can never start clusters locally, which is probably fine since:
+ // 1) We never did this before
+ // 2) We only use this for tests and benchmarks
+ return TopologyGraphDbmsModel.HostedOnMode.SINGLE;
+ }
+
+ @Override
+ public InternalTransaction beginTransaction(
+ KernelTransaction.Type type,
+ LoginContext loginContext,
+ ClientConnectionInfo clientInfo,
+ long timeout,
+ TimeUnit unit,
+ Consumer terminationCallback,
+ TransactionExceptionMapper transactionExceptionMapper
+ ) {
+ return api.beginTransaction(
+ type,
+ loginContext,
+ clientInfo,
+ timeout,
+ unit,
+ terminationCallback,
+ transactionExceptionMapper
+ );
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatIndexQueryImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatIndexQueryImpl.java
new file mode 100644
index 00000000000..143ccbdbdb2
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatIndexQueryImpl.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+
+final class CompatIndexQueryImpl implements CompatIndexQuery {
+ final PropertyIndexQuery indexQuery;
+
+ CompatIndexQueryImpl(PropertyIndexQuery indexQuery) {
+ this.indexQuery = indexQuery;
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatUsernameAuthSubjectImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatUsernameAuthSubjectImpl.java
new file mode 100644
index 00000000000..67ffd47576d
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompatUsernameAuthSubjectImpl.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.CompatUsernameAuthSubject;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+
+final class CompatUsernameAuthSubjectImpl extends CompatUsernameAuthSubject {
+
+ CompatUsernameAuthSubjectImpl(String username, AuthSubject authSubject) {
+ super(username, authSubject);
+ }
+
+ @Override
+ public String executingUser() {
+ return username;
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompositeNodeCursorImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompositeNodeCursorImpl.java
new file mode 100644
index 00000000000..c63636a254d
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/CompositeNodeCursorImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+
+import java.util.List;
+
+public final class CompositeNodeCursorImpl extends CompositeNodeCursor {
+
+ CompositeNodeCursorImpl(List cursors, int[] labelIds) {
+ super(cursors, labelIds);
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseLayoutImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseLayoutImpl.java
new file mode 100644
index 00000000000..a013d2ed0d6
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseLayoutImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.io.layout.DatabaseLayout;
+
+import java.nio.file.Path;
+
+public class GdsDatabaseLayoutImpl implements GdsDatabaseLayout {
+ private final DatabaseLayout databaseLayout;
+
+ public GdsDatabaseLayoutImpl(DatabaseLayout databaseLayout) {this.databaseLayout = databaseLayout;}
+
+ @Override
+ public Path databaseDirectory() {
+ return databaseLayout.databaseDirectory();
+ }
+
+ @Override
+ public Path getTransactionLogsDirectory() {
+ return databaseLayout.getTransactionLogsDirectory();
+ }
+
+ @Override
+ public Path metadataStore() {
+ return databaseLayout.metadataStore();
+ }
+
+ public DatabaseLayout databaseLayout() {
+ return databaseLayout;
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseManagementServiceBuilderImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseManagementServiceBuilderImpl.java
new file mode 100644
index 00000000000..d1556f00eac
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/GdsDatabaseManagementServiceBuilderImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.dbms.api.DatabaseManagementServiceBuilderImplementation;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.graphdb.config.Setting;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+public class GdsDatabaseManagementServiceBuilderImpl implements GdsDatabaseManagementServiceBuilder {
+
+ private final DatabaseManagementServiceBuilderImplementation dbmsBuilder;
+
+ GdsDatabaseManagementServiceBuilderImpl(Path storeDir) {
+ this.dbmsBuilder = new DatabaseManagementServiceBuilderImplementation(storeDir);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfigRaw(Map configMap) {
+ dbmsBuilder.setConfigRaw(configMap);
+ return this;
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder setConfig(Setting setting, S value) {
+ dbmsBuilder.setConfig(setting, value);
+ return this;
+ }
+
+ @Override
+ public DatabaseManagementService build() {
+ return dbmsBuilder.build();
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java
new file mode 100644
index 00000000000..4b7a863afd7
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.Neo4jProxyFactory;
+import org.neo4j.gds.compat.Neo4jVersion;
+
+@ServiceProvider
+public final class Neo4jProxyFactoryImpl implements Neo4jProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_12;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ return new Neo4jProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.12";
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyImpl.java
new file mode 100644
index 00000000000..73752765f09
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/Neo4jProxyImpl.java
@@ -0,0 +1,978 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.neo4j.common.DependencyResolver;
+import org.neo4j.common.EntityType;
+import org.neo4j.configuration.BootloaderSettings;
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.GraphDatabaseSettings;
+import org.neo4j.configuration.SettingValueParsers;
+import org.neo4j.configuration.connectors.ConnectorPortRegister;
+import org.neo4j.configuration.connectors.ConnectorType;
+import org.neo4j.configuration.helpers.DatabaseNameValidator;
+import org.neo4j.dbms.api.DatabaseManagementService;
+import org.neo4j.exceptions.KernelException;
+import org.neo4j.fabric.FabricDatabaseManager;
+import org.neo4j.gds.annotation.SuppressForbidden;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.gds.compat.CompatCallableProcedure;
+import org.neo4j.gds.compat.CompatExecutionMonitor;
+import org.neo4j.gds.compat.CompatIndexQuery;
+import org.neo4j.gds.compat.CompatInput;
+import org.neo4j.gds.compat.CompatUserAggregationFunction;
+import org.neo4j.gds.compat.CompositeNodeCursor;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.gds.compat.GdsDatabaseLayout;
+import org.neo4j.gds.compat.GdsDatabaseManagementServiceBuilder;
+import org.neo4j.gds.compat.GdsGraphDatabaseAPI;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat.InputEntityIdVisitor;
+import org.neo4j.gds.compat.Neo4jProxyApi;
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.gds.compat.TestLog;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Relationship;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.internal.batchimport.AdditionalInitialIds;
+import org.neo4j.internal.batchimport.BatchImporter;
+import org.neo4j.internal.batchimport.BatchImporterFactory;
+import org.neo4j.internal.batchimport.Configuration;
+import org.neo4j.internal.batchimport.IndexConfig;
+import org.neo4j.internal.batchimport.InputIterable;
+import org.neo4j.internal.batchimport.Monitor;
+import org.neo4j.internal.batchimport.input.Collector;
+import org.neo4j.internal.batchimport.input.IdType;
+import org.neo4j.internal.batchimport.input.Input;
+import org.neo4j.internal.batchimport.input.InputEntityVisitor;
+import org.neo4j.internal.batchimport.input.PropertySizeCalculator;
+import org.neo4j.internal.batchimport.input.ReadableGroups;
+import org.neo4j.internal.batchimport.staging.ExecutionMonitor;
+import org.neo4j.internal.batchimport.staging.StageExecution;
+import org.neo4j.internal.helpers.HostnamePort;
+import org.neo4j.internal.id.IdGenerator;
+import org.neo4j.internal.id.IdGeneratorFactory;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.IndexQueryConstraints;
+import org.neo4j.internal.kernel.api.IndexReadSession;
+import org.neo4j.internal.kernel.api.NodeCursor;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.NodeValueIndexCursor;
+import org.neo4j.internal.kernel.api.PropertyCursor;
+import org.neo4j.internal.kernel.api.PropertyIndexQuery;
+import org.neo4j.internal.kernel.api.QueryContext;
+import org.neo4j.internal.kernel.api.Read;
+import org.neo4j.internal.kernel.api.RelationshipScanCursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.internal.kernel.api.TokenPredicate;
+import org.neo4j.internal.kernel.api.TokenSet;
+import org.neo4j.internal.kernel.api.connectioninfo.ClientConnectionInfo;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.FieldSignature;
+import org.neo4j.internal.kernel.api.procs.Neo4jTypes;
+import org.neo4j.internal.kernel.api.procs.ProcedureSignature;
+import org.neo4j.internal.kernel.api.procs.QualifiedName;
+import org.neo4j.internal.kernel.api.procs.UserFunctionSignature;
+import org.neo4j.internal.kernel.api.security.AccessMode;
+import org.neo4j.internal.kernel.api.security.AuthSubject;
+import org.neo4j.internal.kernel.api.security.ReadSecurityPropertyProvider;
+import org.neo4j.internal.kernel.api.security.SecurityContext;
+import org.neo4j.internal.recordstorage.RecordIdType;
+import org.neo4j.internal.schema.IndexCapability;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexOrder;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.io.fs.FileSystemAbstraction;
+import org.neo4j.io.layout.DatabaseLayout;
+import org.neo4j.io.layout.Neo4jLayout;
+import org.neo4j.io.layout.recordstorage.RecordDatabaseLayout;
+import org.neo4j.io.pagecache.PageCache;
+import org.neo4j.io.pagecache.context.CursorContext;
+import org.neo4j.io.pagecache.context.CursorContextFactory;
+import org.neo4j.io.pagecache.context.FixedVersionContextSupplier;
+import org.neo4j.io.pagecache.tracing.PageCacheTracer;
+import org.neo4j.kernel.api.KernelTransaction;
+import org.neo4j.kernel.api.KernelTransactionHandle;
+import org.neo4j.kernel.api.procedure.CallableProcedure;
+import org.neo4j.kernel.api.procedure.CallableUserAggregationFunction;
+import org.neo4j.kernel.api.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
+import org.neo4j.kernel.database.NormalizedDatabaseName;
+import org.neo4j.kernel.impl.coreapi.InternalTransaction;
+import org.neo4j.kernel.impl.index.schema.IndexImporterFactoryImpl;
+import org.neo4j.kernel.impl.query.QueryExecutionConfiguration;
+import org.neo4j.kernel.impl.query.TransactionalContext;
+import org.neo4j.kernel.impl.query.TransactionalContextFactory;
+import org.neo4j.kernel.impl.store.RecordStore;
+import org.neo4j.kernel.impl.store.format.RecordFormatSelector;
+import org.neo4j.kernel.impl.store.format.RecordFormats;
+import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
+import org.neo4j.kernel.impl.transaction.log.EmptyLogTailMetadata;
+import org.neo4j.kernel.impl.transaction.log.files.TransactionLogInitializer;
+import org.neo4j.logging.Log;
+import org.neo4j.logging.internal.LogService;
+import org.neo4j.memory.EmptyMemoryTracker;
+import org.neo4j.procedure.Mode;
+import org.neo4j.scheduler.JobScheduler;
+import org.neo4j.ssl.config.SslPolicyLoader;
+import org.neo4j.storageengine.api.PropertySelection;
+import org.neo4j.storageengine.api.StorageEngineFactory;
+import org.neo4j.util.BitBuffer;
+import org.neo4j.values.storable.TextArray;
+import org.neo4j.values.storable.ValueCategory;
+import org.neo4j.values.storable.Values;
+import org.neo4j.values.virtual.MapValue;
+import org.neo4j.values.virtual.NodeValue;
+import org.neo4j.values.virtual.VirtualValues;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.lang.String.format;
+import static org.neo4j.gds.compat.InternalReadOps.countByIdGenerator;
+
+public final class Neo4jProxyImpl implements Neo4jProxyApi {
+
+ @Override
+ public GdsGraphDatabaseAPI newDb(DatabaseManagementService dbms) {
+ return new CompatGraphDatabaseAPIImpl(dbms);
+ }
+
+ @Override
+ public String validateExternalDatabaseName(String databaseName) {
+ var normalizedName = new NormalizedDatabaseName(databaseName);
+ DatabaseNameValidator.validateExternalDatabaseName(normalizedName);
+ return normalizedName.name();
+ }
+
+ @Override
+ public AccessMode accessMode(CustomAccessMode customAccessMode) {
+ return new CompatAccessModeImpl(customAccessMode) {
+ @Override
+ public boolean allowsReadNodeProperty(
+ Supplier labels,
+ int propertyKey,
+ ReadSecurityPropertyProvider propertyProvider
+ ) {
+ return custom.allowsReadNodeProperty(propertyKey);
+ }
+ };
+ }
+ @Override
+ public String username(AuthSubject subject) {
+ return subject.executingUser();
+ }
+
+ @Override
+ public SecurityContext securityContext(
+ String username,
+ AuthSubject authSubject,
+ AccessMode mode,
+ String databaseName
+ ) {
+ return new SecurityContext(
+ new CompatUsernameAuthSubjectImpl(username, authSubject),
+ mode,
+ // GDS is always operating from an embedded context
+ ClientConnectionInfo.EMBEDDED_CONNECTION,
+ databaseName
+ );
+ }
+
+ @Override
+ public long getHighId(RecordStore extends AbstractBaseRecord> recordStore) {
+ return recordStore.getIdGenerator().getHighId();
+ }
+
+ @Override
+ public List> entityCursorScan(
+ KernelTransaction transaction,
+ int[] labelIds,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelIds);
+ } else {
+ var read = transaction.dataRead();
+ return Arrays
+ .stream(labelIds)
+ .mapToObj(read::nodeLabelScan)
+ .map(scan -> scanToStoreScan(scan, batchSize))
+ .collect(Collectors.toList());
+ }
+ }
+
+ @Override
+ public PropertyCursor allocatePropertyCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocatePropertyCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public PropertyReference propertyReference(NodeCursor nodeCursor) {
+ return ReferencePropertyReference.of(nodeCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference propertyReference(RelationshipScanCursor relationshipScanCursor) {
+ return ReferencePropertyReference.of(relationshipScanCursor.propertiesReference());
+ }
+
+ @Override
+ public PropertyReference noPropertyReference() {
+ return ReferencePropertyReference.empty();
+ }
+
+ @Override
+ public void nodeProperties(
+ KernelTransaction kernelTransaction,
+ long nodeReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .nodeProperties(nodeReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public void relationshipProperties(
+ KernelTransaction kernelTransaction,
+ long relationshipReference,
+ PropertyReference reference,
+ PropertyCursor cursor
+ ) {
+ var neoReference = ((ReferencePropertyReference) reference).reference;
+ kernelTransaction
+ .dataRead()
+ .relationshipProperties(relationshipReference, neoReference, PropertySelection.ALL_PROPERTIES, cursor);
+ }
+
+ @Override
+ public NodeCursor allocateNodeCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public RelationshipScanCursor allocateRelationshipScanCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateRelationshipScanCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeLabelIndexCursor allocateNodeLabelIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction.cursors().allocateNodeLabelIndexCursor(kernelTransaction.cursorContext());
+ }
+
+ @Override
+ public NodeValueIndexCursor allocateNodeValueIndexCursor(KernelTransaction kernelTransaction) {
+ return kernelTransaction
+ .cursors()
+ .allocateNodeValueIndexCursor(kernelTransaction.cursorContext(), kernelTransaction.memoryTracker());
+ }
+
+ @Override
+ public boolean hasNodeLabelIndex(KernelTransaction kernelTransaction) {
+ return NodeLabelIndexLookupImpl.hasNodeLabelIndex(kernelTransaction);
+ }
+
+ @Override
+ public StoreScan nodeLabelIndexScan(
+ KernelTransaction transaction,
+ int labelId,
+ int batchSize,
+ boolean allowPartitionedScan
+ ) {
+ if (allowPartitionedScan) {
+ return partitionedNodeLabelIndexScan(transaction, batchSize, labelId).get(0);
+ } else {
+ var read = transaction.dataRead();
+ return scanToStoreScan(read.nodeLabelScan(labelId), batchSize);
+ }
+ }
+
+ @Override
+ public StoreScan scanToStoreScan(Scan scan, int batchSize) {
+ return new ScanBasedStoreScanImpl<>(scan, batchSize);
+ }
+
+ private List> partitionedNodeLabelIndexScan(
+ KernelTransaction transaction,
+ int batchSize,
+ int... labelIds
+ ) {
+ var indexDescriptor = NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ );
+
+ if (indexDescriptor == IndexDescriptor.NO_INDEX) {
+ throw new IllegalStateException("There is no index that can back a node label scan.");
+ }
+
+ var read = transaction.dataRead();
+
+ // Our current strategy is to select the token with the highest count
+ // and use that one as the driving partitioned index scan. The partitions
+ // of all other partitioned index scans will be aligned to that one.
+ int maxToken = labelIds[0];
+ long maxCount = read.countsForNodeWithoutTxState(labelIds[0]);
+
+ for (int i = 1; i < labelIds.length; i++) {
+ long count = read.countsForNodeWithoutTxState(labelIds[i]);
+ if (count > maxCount) {
+ maxCount = count;
+ maxToken = labelIds[i];
+ }
+ }
+
+ int numberOfPartitions = PartitionedStoreScan.getNumberOfPartitions(maxCount, batchSize);
+
+ try {
+ var session = read.tokenReadSession(indexDescriptor);
+
+ var partitionedScan = read.nodeLabelScan(
+ session,
+ numberOfPartitions,
+ transaction.cursorContext(),
+ new TokenPredicate(maxToken)
+ );
+
+ var scans = new ArrayList>(labelIds.length);
+ scans.add(new PartitionedStoreScan(partitionedScan));
+
+ // Initialize the remaining index scans with the partitioning of the first scan.
+ for (int labelToken : labelIds) {
+ if (labelToken != maxToken) {
+ var scan = read.nodeLabelScan(session, partitionedScan, new TokenPredicate(labelToken));
+ scans.add(new PartitionedStoreScan(scan));
+ }
+ }
+
+ return scans;
+ } catch (KernelException e) {
+ // should not happen, we check for the index existence and applicability
+ // before reading it
+ throw new RuntimeException("Unexpected error while initialising reading from node label index", e);
+ }
+ }
+
+ @Override
+ public CompatIndexQuery rangeIndexQuery(
+ int propertyKeyId,
+ double from,
+ boolean fromInclusive,
+ double to,
+ boolean toInclusive
+ ) {
+ return new CompatIndexQueryImpl(PropertyIndexQuery.range(propertyKeyId, from, fromInclusive, to, toInclusive));
+ }
+
+ @Override
+ public CompatIndexQuery rangeAllIndexQuery(int propertyKeyId) {
+ var rangePredicate = PropertyIndexQuery.range(
+ propertyKeyId,
+ Values.doubleValue(Double.NEGATIVE_INFINITY),
+ true,
+ Values.doubleValue(Double.POSITIVE_INFINITY),
+ true
+ );
+ return new CompatIndexQueryImpl(rangePredicate);
+ }
+
+ @Override
+ public void nodeIndexSeek(
+ Read dataRead,
+ IndexReadSession index,
+ NodeValueIndexCursor cursor,
+ IndexOrder indexOrder,
+ boolean needsValues,
+ CompatIndexQuery query
+ ) throws KernelException {
+ var indexQueryConstraints = indexOrder == IndexOrder.NONE
+ ? IndexQueryConstraints.unordered(needsValues)
+ : IndexQueryConstraints.constrained(indexOrder, needsValues);
+
+ dataRead.nodeIndexSeek(
+ (QueryContext) dataRead,
+ index,
+ cursor,
+ indexQueryConstraints,
+ ((CompatIndexQueryImpl) query).indexQuery
+ );
+ }
+
+ @Override
+ public CompositeNodeCursor compositeNodeCursor(List cursors, int[] labelIds) {
+ return new CompositeNodeCursorImpl(cursors, labelIds);
+ }
+
+ @Override
+ public Configuration batchImporterConfig(
+ int batchSize,
+ int writeConcurrency,
+ Optional pageCacheMemory,
+ boolean highIO,
+ IndexConfig indexConfig
+ ) {
+ return new org.neo4j.internal.batchimport.Configuration() {
+ @Override
+ public int batchSize() {
+ return batchSize;
+ }
+
+ @Override
+ public int maxNumberOfWorkerThreads() {
+ return writeConcurrency;
+ }
+
+ @Override
+ public boolean highIO() {
+ return highIO;
+ }
+
+ @Override
+ public IndexConfig indexConfig() {
+ return indexConfig;
+ }
+ };
+ }
+
+ @Override
+ public int writeConcurrency(Configuration batchImportConfiguration) {
+ return batchImportConfiguration.maxNumberOfWorkerThreads();
+ }
+
+ @Override
+ public BatchImporter instantiateBatchImporter(
+ BatchImporterFactory factory,
+ GdsDatabaseLayout directoryStructure,
+ FileSystemAbstraction fileSystem,
+ PageCacheTracer pageCacheTracer,
+ Configuration configuration,
+ LogService logService,
+ ExecutionMonitor executionMonitor,
+ AdditionalInitialIds additionalInitialIds,
+ Config dbConfig,
+ RecordFormats recordFormats,
+ JobScheduler jobScheduler,
+ Collector badCollector
+ ) {
+ dbConfig.set(GraphDatabaseSettings.db_format, recordFormats.name());
+ var databaseLayout = ((GdsDatabaseLayoutImpl) directoryStructure).databaseLayout();
+ return factory.instantiate(
+ databaseLayout,
+ fileSystem,
+ pageCacheTracer,
+ configuration,
+ logService,
+ executionMonitor,
+ additionalInitialIds,
+ new EmptyLogTailMetadata(dbConfig),
+ dbConfig,
+ Monitor.NO_MONITOR,
+ jobScheduler,
+ badCollector,
+ TransactionLogInitializer.getLogFilesInitializer(),
+ new IndexImporterFactoryImpl(),
+ EmptyMemoryTracker.INSTANCE,
+ new CursorContextFactory(PageCacheTracer.NULL, FixedVersionContextSupplier.EMPTY_CONTEXT_SUPPLIER)
+ );
+ }
+
+ @Override
+ public Input batchInputFrom(CompatInput compatInput) {
+ return new InputFromCompatInput(compatInput);
+ }
+
+ @Override
+ public InputEntityIdVisitor.Long inputEntityLongIdVisitor(IdType idType, ReadableGroups groups) {
+ switch (idType) {
+ case ACTUAL -> {
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id);
+ }
+ };
+ }
+ case INTEGER -> {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.Long() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, long id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, long id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, long id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+ default -> throw new IllegalStateException("Unexpected value: " + idType);
+ }
+ }
+
+ @Override
+ public InputEntityIdVisitor.String inputEntityStringIdVisitor(ReadableGroups groups) {
+ var globalGroup = groups.get(null);
+
+ return new InputEntityIdVisitor.String() {
+ @Override
+ public void visitNodeId(InputEntityVisitor visitor, String id) {
+ visitor.id(id, globalGroup);
+ }
+
+ @Override
+ public void visitSourceId(InputEntityVisitor visitor, String id) {
+ visitor.startId(id, globalGroup);
+ }
+
+ @Override
+ public void visitTargetId(InputEntityVisitor visitor, String id) {
+ visitor.endId(id, globalGroup);
+ }
+ };
+ }
+
+ @Override
+ public Setting additionalJvm() {
+ return BootloaderSettings.additional_jvm;
+ }
+
+ @Override
+ public Setting pageCacheMemory() {
+ return GraphDatabaseSettings.pagecache_memory;
+ }
+
+ @Override
+ public Long pageCacheMemoryValue(String value) {
+ return SettingValueParsers.BYTES.parse(value);
+ }
+
+ @Override
+ public ProcedureSignature procedureSignature(
+ QualifiedName name,
+ List inputSignature,
+ List outputSignature,
+ Mode mode,
+ boolean admin,
+ String deprecated,
+ String description,
+ String warning,
+ boolean eager,
+ boolean caseInsensitive,
+ boolean systemProcedure,
+ boolean internal,
+ boolean allowExpiredCredentials,
+ boolean threadSafe
+ ) {
+ return new ProcedureSignature(
+ name,
+ inputSignature,
+ outputSignature,
+ mode,
+ admin,
+ deprecated,
+ description,
+ warning,
+ eager,
+ caseInsensitive,
+ systemProcedure,
+ internal,
+ allowExpiredCredentials,
+ threadSafe
+ );
+ }
+
+ @Override
+ public long getHighestPossibleNodeCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.NODE).orElseGet(read::nodesGetCount);
+ }
+
+ @Override
+ public long getHighestPossibleRelationshipCount(
+ Read read, IdGeneratorFactory idGeneratorFactory
+ ) {
+ return countByIdGenerator(idGeneratorFactory, RecordIdType.RELATIONSHIP).orElseGet(read::relationshipsGetCount);
+ }
+
+ @Override
+ public String versionLongToString(long storeVersion) {
+ // copied from org.neo4j.kernel.impl.store.LegacyMetadataHandler.versionLongToString which is private
+ if (storeVersion == -1) {
+ return "Unknown";
+ }
+ BitBuffer bits = BitBuffer.bitsFromLongs(new long[]{storeVersion});
+ int length = bits.getShort(8);
+ if (length == 0 || length > 7) {
+ throw new IllegalArgumentException(format(Locale.ENGLISH, "The read version string length %d is not proper.", length));
+ }
+ char[] result = new char[length];
+ for (int i = 0; i < length; i++) {
+ result[i] = (char) bits.getShort(8);
+ }
+ return new String(result);
+ }
+
+ private static final class InputFromCompatInput implements Input {
+ private final CompatInput delegate;
+
+ private InputFromCompatInput(CompatInput delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public InputIterable nodes(Collector badCollector) {
+ return delegate.nodes(badCollector);
+ }
+
+ @Override
+ public InputIterable relationships(Collector badCollector) {
+ return delegate.relationships(badCollector);
+ }
+
+ @Override
+ public IdType idType() {
+ return delegate.idType();
+ }
+
+ @Override
+ public ReadableGroups groups() {
+ return delegate.groups();
+ }
+
+ @Override
+ public Estimates calculateEstimates(PropertySizeCalculator propertySizeCalculator) throws IOException {
+ return delegate.calculateEstimates((values, kernelTransaction) -> propertySizeCalculator.calculateSize(
+ values,
+ kernelTransaction.cursorContext(),
+ kernelTransaction.memoryTracker()
+ ));
+ }
+ }
+
+ @Override
+ public TestLog testLog() {
+ return new TestLogImpl();
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getUserLog(LogService logService, Class> loggingClass) {
+ return logService.getUserLog(loggingClass);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Log getInternalLog(LogService logService, Class> loggingClass) {
+ return logService.getInternalLog(loggingClass);
+ }
+
+ @Override
+ public NodeValue nodeValue(long id, TextArray labels, MapValue properties) {
+ return VirtualValues.nodeValue(id, String.valueOf(id), labels, properties);
+ }
+
+ @Override
+ public Relationship virtualRelationship(long id, Node startNode, Node endNode, RelationshipType type) {
+ return new VirtualRelationshipImpl(id, startNode, endNode, type);
+ }
+
+ @Override
+ public GdsDatabaseManagementServiceBuilder databaseManagementServiceBuilder(Path storeDir) {
+ return new GdsDatabaseManagementServiceBuilderImpl(storeDir);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats selectRecordFormatForStore(
+ DatabaseLayout databaseLayout,
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ return RecordFormatSelector.selectForStore(
+ (RecordDatabaseLayout) databaseLayout,
+ fs,
+ pageCache,
+ logService.getInternalLogProvider(),
+ new CursorContextFactory(pageCacheTracer, FixedVersionContextSupplier.EMPTY_CONTEXT_SUPPLIER)
+ );
+ }
+
+ @Override
+ public boolean isNotNumericIndex(IndexCapability indexCapability) {
+ return !indexCapability.areValueCategoriesAccepted(ValueCategory.NUMBER);
+ }
+
+ @Override
+ public void setAllowUpgrades(Config.Builder configBuilder, boolean value) {
+ }
+
+ @Override
+ public String defaultRecordFormatSetting() {
+ return GraphDatabaseSettings.db_format.defaultValue();
+ }
+
+ @Override
+ public void configureRecordFormat(Config.Builder configBuilder, String recordFormat) {
+ var databaseRecordFormat = recordFormat.toLowerCase(Locale.ENGLISH);
+ configBuilder.set(GraphDatabaseSettings.db_format, databaseRecordFormat);
+ }
+
+ @Override
+ public GdsDatabaseLayout databaseLayout(Config config, String databaseName) {
+ var storageEngineFactory = StorageEngineFactory.selectStorageEngine(config);
+ var dbLayout = neo4jLayout(config).databaseLayout(databaseName);
+ var databaseLayout = storageEngineFactory.formatSpecificDatabaseLayout(dbLayout);
+ return new GdsDatabaseLayoutImpl(databaseLayout);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public Neo4jLayout neo4jLayout(Config config) {
+ return Neo4jLayout.of(config);
+ }
+
+ @Override
+ public BoltTransactionRunner, ?> boltTransactionRunner() {
+ return new BoltTransactionRunnerImpl();
+ }
+
+ @Override
+ public HostnamePort getLocalBoltAddress(ConnectorPortRegister connectorPortRegister) {
+ return connectorPortRegister.getLocalAddress(ConnectorType.BOLT);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public SslPolicyLoader createSllPolicyLoader(
+ FileSystemAbstraction fileSystem,
+ Config config,
+ LogService logService
+ ) {
+ return SslPolicyLoader.create(fileSystem, config, logService.getInternalLogProvider());
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat specific use")
+ public RecordFormats recordFormatSelector(
+ String databaseName,
+ Config databaseConfig,
+ FileSystemAbstraction fs,
+ LogService logService,
+ GraphDatabaseService databaseService
+ ) {
+ var neo4jLayout = Neo4jLayout.of(databaseConfig);
+ var recordDatabaseLayout = RecordDatabaseLayout.of(neo4jLayout, databaseName);
+ return RecordFormatSelector.selectForStoreOrConfigForNewDbs(
+ databaseConfig,
+ recordDatabaseLayout,
+ fs,
+ GraphDatabaseApiProxy.resolveDependency(databaseService, PageCache.class),
+ logService.getInternalLogProvider(),
+ GraphDatabaseApiProxy.resolveDependency(databaseService, CursorContextFactory.class)
+ );
+ }
+
+ @Override
+ public ExecutionMonitor executionMonitor(CompatExecutionMonitor compatExecutionMonitor) {
+ return new ExecutionMonitor.Adapter(
+ compatExecutionMonitor.checkIntervalMillis(),
+ TimeUnit.MILLISECONDS
+ ) {
+
+ @Override
+ public void initialize(DependencyResolver dependencyResolver) {
+ compatExecutionMonitor.initialize(dependencyResolver);
+ }
+
+ @Override
+ public void start(StageExecution execution) {
+ compatExecutionMonitor.start(execution);
+ }
+
+ @Override
+ public void end(StageExecution execution, long totalTimeMillis) {
+ compatExecutionMonitor.end(execution, totalTimeMillis);
+ }
+
+ @Override
+ public void done(boolean successful, long totalTimeMillis, String additionalInformation) {
+ compatExecutionMonitor.done(successful, totalTimeMillis, additionalInformation);
+ }
+
+ @Override
+ public void check(StageExecution execution) {
+ compatExecutionMonitor.check(execution);
+ }
+ };
+ }
+
+ @Override
+ @SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE") // We assign nulls because it makes the code more readable
+ public UserFunctionSignature userFunctionSignature(
+ QualifiedName name,
+ List inputSignature,
+ Neo4jTypes.AnyType type,
+ String description,
+ boolean internal,
+ boolean threadSafe,
+ Optional deprecatedBy
+ ) {
+ String category = null; // No predefined categpry (like temporal or math)
+ var caseInsensitive = false; // case sensitive name match
+ var isBuiltIn = false; // is built in; never true for GDS
+
+ return new UserFunctionSignature(
+ name,
+ inputSignature,
+ type,
+ deprecatedBy.orElse(null),
+ description,
+ category,
+ caseInsensitive,
+ isBuiltIn,
+ internal,
+ threadSafe
+ );
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableProcedure callableProcedure(CompatCallableProcedure procedure) {
+ return new CallableProcedureImpl(procedure);
+ }
+
+ @Override
+ @SuppressForbidden(reason = "This is the compat API")
+ public CallableUserAggregationFunction callableUserAggregationFunction(CompatUserAggregationFunction function) {
+ return new CallableUserAggregationFunctionImpl(function);
+ }
+
+ @Override
+ public long transactionId(KernelTransactionHandle kernelTransactionHandle) {
+ return kernelTransactionHandle.getTransactionSequenceNumber();
+ }
+
+ @Override
+ public void reserveNeo4jIds(IdGeneratorFactory generatorFactory, int size, CursorContext cursorContext) {
+ IdGenerator idGenerator = generatorFactory.get(RecordIdType.NODE);
+
+ idGenerator.nextConsecutiveIdRange(size, false, cursorContext);
+ }
+
+ @Override
+ public TransactionalContext newQueryContext(
+ TransactionalContextFactory contextFactory,
+ InternalTransaction tx,
+ String queryText,
+ MapValue queryParameters
+ ) {
+ return contextFactory.newContext(tx, queryText, queryParameters, QueryExecutionConfiguration.DEFAULT_CONFIG);
+ }
+
+ @Override
+ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
+ var databaseManager = GraphDatabaseApiProxy.resolveDependency(databaseService, FabricDatabaseManager.class);
+ return databaseManager.isFabricDatabase(GraphDatabaseApiProxy.databaseId(databaseService));
+ }
+
+ @Override
+ public T lookupComponentProvider(Context ctx, Class component, boolean safe) throws ProcedureException {
+ var globalProcedures = GraphDatabaseApiProxy.resolveDependency(ctx.dependencyResolver(), GlobalProcedures.class);
+ return globalProcedures.getCurrentView().lookupComponentProvider(component, safe).apply(ctx);
+ }
+
+ @Override
+ public GlobalProcedureRegistry globalProcedureRegistry(GlobalProcedures globalProcedures) {
+ return new GlobalProcedureRegistry() {
+ @Override
+ public Set getAllProcedures() {
+ return globalProcedures.getCurrentView().getAllProcedures();
+ }
+
+ @Override
+ public Stream getAllNonAggregatingFunctions() {
+ return globalProcedures.getCurrentView().getAllNonAggregatingFunctions();
+ }
+
+ @Override
+ public Stream getAllAggregatingFunctions() {
+ return globalProcedures.getCurrentView().getAllAggregatingFunctions();
+ }
+ };
+ }
+
+ private static final DependencyResolver EMPTY_DEPENDENCY_RESOLVER = new DependencyResolver() {
+ @Override
+ public T resolveDependency(Class type, SelectionStrategy selector) {
+ return null;
+ }
+
+ @Override
+ public boolean containsDependency(Class> type) {
+ return false;
+ }
+ };
+
+ @Override
+ public DependencyResolver emptyDependencyResolver() {
+ return EMPTY_DEPENDENCY_RESOLVER;
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/NodeLabelIndexLookupImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/NodeLabelIndexLookupImpl.java
new file mode 100644
index 00000000000..58d54c38069
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/NodeLabelIndexLookupImpl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.common.EntityType;
+import org.neo4j.internal.kernel.api.InternalIndexState;
+import org.neo4j.internal.kernel.api.SchemaRead;
+import org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException;
+import org.neo4j.internal.schema.IndexDescriptor;
+import org.neo4j.internal.schema.IndexType;
+import org.neo4j.internal.schema.SchemaDescriptor;
+import org.neo4j.internal.schema.SchemaDescriptors;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class NodeLabelIndexLookupImpl {
+
+ static boolean hasNodeLabelIndex(KernelTransaction transaction) {
+ return NodeLabelIndexLookupImpl.findUsableMatchingIndex(
+ transaction,
+ SchemaDescriptors.forAnyEntityTokens(EntityType.NODE)
+ ) != IndexDescriptor.NO_INDEX;
+ }
+
+ static IndexDescriptor findUsableMatchingIndex(
+ KernelTransaction transaction,
+ SchemaDescriptor schemaDescriptor
+ ) {
+ var schemaRead = transaction.schemaRead();
+ var iterator = schemaRead.index(schemaDescriptor);
+ while (iterator.hasNext()) {
+ var index = iterator.next();
+ if (index.getIndexType() == IndexType.LOOKUP && indexIsOnline(schemaRead, index)) {
+ return index;
+ }
+ }
+ return IndexDescriptor.NO_INDEX;
+ }
+
+ private static boolean indexIsOnline(SchemaRead schemaRead, IndexDescriptor index) {
+ var state = InternalIndexState.FAILED;
+ try {
+ state = schemaRead.indexGetState(index);
+ } catch (IndexNotFoundKernelException e) {
+ // Well the index should always exist here, but if we didn't find it while checking the state,
+ // then we obviously don't want to use it.
+ }
+ return state == InternalIndexState.ONLINE;
+ }
+
+ private NodeLabelIndexLookupImpl() {}
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/PartitionedStoreScan.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/PartitionedStoreScan.java
new file mode 100644
index 00000000000..365e85330d6
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/PartitionedStoreScan.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.NodeLabelIndexCursor;
+import org.neo4j.internal.kernel.api.PartitionedScan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+final class PartitionedStoreScan implements StoreScan {
+ private final PartitionedScan scan;
+
+ PartitionedStoreScan(PartitionedScan scan) {
+ this.scan = scan;
+ }
+
+ static int getNumberOfPartitions(long nodeCount, int batchSize) {
+ int numberOfPartitions;
+ if (nodeCount > 0) {
+ // ceil div to try to get enough partitions so a single one does
+ // not include more nodes than batchSize
+ long partitions = ((nodeCount - 1) / batchSize) + 1;
+
+ // value must be positive
+ if (partitions < 1) {
+ partitions = 1;
+ }
+
+ numberOfPartitions = (int) Long.min(Integer.MAX_VALUE, partitions);
+ } else {
+ // we have no partitions to scan, but the value must still be positive
+ numberOfPartitions = 1;
+ }
+ return numberOfPartitions;
+ }
+
+ @Override
+ public boolean reserveBatch(NodeLabelIndexCursor cursor, KernelTransaction ktx) {
+ return scan.reservePartition(cursor, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ReferencePropertyReference.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ReferencePropertyReference.java
new file mode 100644
index 00000000000..ee12df9ca66
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ReferencePropertyReference.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.PropertyReference;
+import org.neo4j.storageengine.api.Reference;
+
+import java.util.Objects;
+
+public final class ReferencePropertyReference implements PropertyReference {
+
+ private static final PropertyReference EMPTY = new ReferencePropertyReference(null);
+
+ public final Reference reference;
+
+ private ReferencePropertyReference(Reference reference) {
+ this.reference = reference;
+ }
+
+ public static PropertyReference of(Reference reference) {
+ return new ReferencePropertyReference(Objects.requireNonNull(reference));
+ }
+
+ public static PropertyReference empty() {
+ return EMPTY;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return reference == null;
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ScanBasedStoreScanImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ScanBasedStoreScanImpl.java
new file mode 100644
index 00000000000..9319f2f4234
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/ScanBasedStoreScanImpl.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.gds.compat.StoreScan;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.Scan;
+import org.neo4j.kernel.api.KernelTransaction;
+
+public final class ScanBasedStoreScanImpl implements StoreScan {
+ private final Scan scan;
+ private final int batchSize;
+
+ public ScanBasedStoreScanImpl(Scan scan, int batchSize) {
+ this.scan = scan;
+ this.batchSize = batchSize;
+ }
+
+ @Override
+ public boolean reserveBatch(C cursor, KernelTransaction ktx) {
+ return scan.reserveBatch(cursor, batchSize, ktx.cursorContext(), ktx.securityContext().mode());
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java
new file mode 100644
index 00000000000..52e994f8e91
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyFactoryImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.annotations.service.ServiceProvider;
+import org.neo4j.gds.compat.Neo4jVersion;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.gds.compat.SettingProxyFactory;
+
+@ServiceProvider
+public final class SettingProxyFactoryImpl implements SettingProxyFactory {
+
+ @Override
+ public boolean canLoad(Neo4jVersion version) {
+ return version == Neo4jVersion.V_5_12;
+ }
+
+ @Override
+ public SettingProxyApi load() {
+ return new SettingProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j Settings 5.12";
+ }
+}
diff --git a/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyImpl.java b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyImpl.java
new file mode 100644
index 00000000000..8ef4811ea9e
--- /dev/null
+++ b/compatibility/5.12/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_512/SettingProxyImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.neo4j.gds.compat._512;
+
+import org.neo4j.configuration.Config;
+import org.neo4j.configuration.SettingBuilder;
+import org.neo4j.dbms.systemgraph.TopologyGraphDbmsModel;
+import org.neo4j.gds.compat.DatabaseMode;
+import org.neo4j.gds.compat.SettingProxyApi;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.config.Setting;
+import org.neo4j.kernel.impl.factory.GraphDatabaseFacade;
+import org.neo4j.kernel.internal.GraphDatabaseAPI;
+
+public class SettingProxyImpl implements SettingProxyApi {
+
+ @Override
+ public Setting setting(org.neo4j.gds.compat.Setting