diff --git a/README.adoc b/README.adoc
index f680c0e4b6..040a3d8206 100644
--- a/README.adoc
+++ b/README.adoc
@@ -26,10 +26,12 @@ When installing GDS manually, please refer to the below compatibility matrix:
.Compatibility matrix (italicized version is in development)
|===
|GDS version | Neo4j version | Java Version
-.10+<.^|_GDS 2.6.x_ (preview)
+.11+<.^|_GDS 2.6.x_ (preview)
+|Neo4j 5.15.0
+.2+.^|Java 21 & Java 17
|Neo4j 5.14.0
-.9+.^|Java 17
|Neo4j 5.13.0
+.8+.^|Java 17
|Neo4j 5.12.0
|Neo4j 5.11.0
|Neo4j 5.10.0
@@ -39,10 +41,12 @@ When installing GDS manually, please refer to the below compatibility matrix:
|Neo4j 5.6.0
|Neo4j 4.4.9 - 4.4.28
.1+.^|Java 11
-.10+<.^|GDS 2.5.x
+.11+<.^|GDS 2.5.x
+|Neo4j 5.15.0
+.2+.^|Java 21 & Java 17
|Neo4j 5.14.0
-.9+.^|Java 17
|Neo4j 5.13.0
+.8+.^|Java 17
|Neo4j 5.12.0
|Neo4j 5.11.0
|Neo4j 5.10.0
diff --git a/build.gradle b/build.gradle
index 2bdc490a7d..08b460c9ad 100644
--- a/build.gradle
+++ b/build.gradle
@@ -38,6 +38,7 @@ ext {
project(':neo4j-kernel-adapter-5.12'),
project(':neo4j-kernel-adapter-5.13'),
project(':neo4j-kernel-adapter-5.14'),
+ project(':neo4j-kernel-adapter-5.15'),
],
'storage-engine-adapter': [
project(':storage-engine-adapter-4.4'),
@@ -50,6 +51,7 @@ ext {
project(':storage-engine-adapter-5.12'),
project(':storage-engine-adapter-5.13'),
project(':storage-engine-adapter-5.14'),
+ project(':storage-engine-adapter-5.15'),
]
]
}
diff --git a/compatibility/5.15/neo4j-kernel-adapter/build.gradle b/compatibility/5.15/neo4j-kernel-adapter/build.gradle
new file mode 100644
index 0000000000..e1974370ac
--- /dev/null
+++ b/compatibility/5.15/neo4j-kernel-adapter/build.gradle
@@ -0,0 +1,67 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Neo4j Kernel Adapter 5.15'
+
+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.15'
+
+ 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.15'
+ compileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.15'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.15'
+ compileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.15'
+
+ implementation project(':neo4j-kernel-adapter-api')
+ implementation project(':neo4j-kernel-adapter-5-common')
+ }
+} 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.15'
+
+ java17CompileOnly project(':annotations')
+ java17CompileOnly group: 'org.immutables', name: 'value-annotations', version: ver.'immutables'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j', version: neos.'5.15'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.15'
+ java17CompileOnly group: 'org.neo4j.community', name: 'it-test-support', version: neos.'5.15'
+ java17CompileOnly group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: ver.'spotbugsToolVersion'
+
+ java17Implementation project(':neo4j-kernel-adapter-api')
+ java17Implementation project(':neo4j-kernel-adapter-5-common')
+ }
+}
diff --git a/compatibility/5.15/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_515/Neo4jProxyFactoryImpl.java b/compatibility/5.15/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_515/Neo4jProxyFactoryImpl.java
new file mode 100644
index 0000000000..ba57fff81e
--- /dev/null
+++ b/compatibility/5.15/neo4j-kernel-adapter/src/main/java/org/neo4j/gds/compat/_515/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._515;
+
+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.15 compatibility requires JDK17");
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.15 (placeholder)";
+ }
+}
diff --git a/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/BoltTransactionRunnerImpl.java b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/BoltTransactionRunnerImpl.java
new file mode 100644
index 0000000000..4c32d7eac6
--- /dev/null
+++ b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/Neo4jProxyFactoryImpl.java b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/Neo4jProxyFactoryImpl.java
new file mode 100644
index 0000000000..00fd7cec70
--- /dev/null
+++ b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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_15;
+ }
+
+ @Override
+ public Neo4jProxyApi load() {
+ return new Neo4jProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Neo4j 5.15";
+ }
+}
diff --git a/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/Neo4jProxyImpl.java b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/Neo4jProxyImpl.java
new file mode 100644
index 0000000000..77c197cb37
--- /dev/null
+++ b/compatibility/5.15/neo4j-kernel-adapter/src/main/java17/org/neo4j/gds/compat/_515/Neo4jProxyImpl.java
@@ -0,0 +1,223 @@
+/*
+ * 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._515;
+
+import org.neo4j.common.DependencyResolver;
+import org.neo4j.gds.compat.BoltTransactionRunner;
+import org.neo4j.gds.compat.CompatExecutionContext;
+import org.neo4j.gds.compat.CustomAccessMode;
+import org.neo4j.gds.compat.GlobalProcedureRegistry;
+import org.neo4j.gds.compat.GraphDatabaseApiProxy;
+import org.neo4j.gds.compat._5x.CommonNeo4jProxyImpl;
+import org.neo4j.gds.compat._5x.CompatAccessModeImpl;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.internal.kernel.api.Cursor;
+import org.neo4j.internal.kernel.api.PartitionedScan;
+import org.neo4j.internal.kernel.api.TokenSet;
+import org.neo4j.internal.kernel.api.exceptions.ProcedureException;
+import org.neo4j.internal.kernel.api.procs.FieldSignature;
+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.ReadSecurityPropertyProvider;
+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.procedure.Context;
+import org.neo4j.kernel.api.procedure.GlobalProcedures;
+import org.neo4j.kernel.database.DatabaseReferenceImpl;
+import org.neo4j.kernel.database.DatabaseReferenceRepository;
+import org.neo4j.kernel.impl.store.RecordStore;
+import org.neo4j.kernel.impl.store.record.AbstractBaseRecord;
+import org.neo4j.procedure.Mode;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public final class Neo4jProxyImpl extends CommonNeo4jProxyImpl {
+
+ @Override
+ public long getHighId(RecordStore extends AbstractBaseRecord> recordStore) {
+ return recordStore.getIdGenerator().getHighId();
+ }
+
+ @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 BoltTransactionRunner, ?> boltTransactionRunner() {
+ return new BoltTransactionRunnerImpl();
+ }
+
+ @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 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;
+ }
+
+ @Override
+ public CursorContextFactory cursorContextFactory(Optional pageCacheTracer) {
+ return pageCacheTracer.map(cacheTracer -> new CursorContextFactory(
+ cacheTracer,
+ FixedVersionContextSupplier.EMPTY_CONTEXT_SUPPLIER
+ )).orElse(CursorContextFactory.NULL_CONTEXT_FACTORY);
+ }
+
+ @Override
+ public CompatExecutionContext executionContext(KernelTransaction ktx) {
+ var stmt = ktx.acquireStatement();
+ var ctx = ktx.createExecutionContext();
+ return new CompatExecutionContext() {
+ @Override
+ public CursorContext cursorContext() {
+ return ctx.cursorContext();
+ }
+
+ @Override
+ public AccessMode accessMode() {
+ return ctx.securityContext().mode();
+ }
+
+ @Override
+ public boolean reservePartition(PartitionedScan scan, C cursor) {
+ return scan.reservePartition(cursor, ctx);
+ }
+
+ @Override
+ public void close() {
+ ctx.complete();
+ ctx.close();
+ stmt.close();
+ }
+ };
+ }
+
+ @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 neo4jArrowServerAddressHeader() {
+ // TODO: replace this with a dependency to neo4j once we moved the corresponding piece to a public module
+ return "ArrowPluginAddress";
+ }
+
+ @Override
+ public String metricsManagerClass() {
+ return "com.neo4j.metrics.MetricsManager";
+ }
+
+ @Override
+ public boolean isCompositeDatabase(GraphDatabaseService databaseService) {
+ var databaseId = GraphDatabaseApiProxy.databaseId(databaseService);
+ var repo = GraphDatabaseApiProxy.resolveDependency(databaseService, DatabaseReferenceRepository.class);
+ return repo.getCompositeDatabaseReferences().stream()
+ .map(DatabaseReferenceImpl.Internal::databaseId)
+ .anyMatch(databaseId::equals);
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/build.gradle b/compatibility/5.15/storage-engine-adapter/build.gradle
new file mode 100644
index 0000000000..8f1c8fa2c3
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/build.gradle
@@ -0,0 +1,67 @@
+apply plugin: 'java-library'
+apply plugin: 'me.champeau.mrjar'
+
+description = 'Neo4j Graph Data Science :: Storage Engine Adapter 5.15'
+
+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.15'
+
+ 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.15'
+ compileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.15'
+
+ 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(':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.15'
+
+ 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.15'
+ java17CompileOnly group: 'org.neo4j', name: 'neo4j-record-storage-engine', version: neos.'5.15'
+
+ java17Implementation project(':core')
+ java17Implementation project(':storage-engine-adapter-api')
+ java17Implementation project(':config-api')
+ java17Implementation project(':string-formatting')
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/InMemoryStorageEngineFactory.java b/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/InMemoryStorageEngineFactory.java
new file mode 100644
index 0000000000..dd89f09ee5
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/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._515;
+
+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 "unsupported515";
+ }
+
+ @Override
+ public StoreVersionCheck versionCheck(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ Config config,
+ PageCache pageCache,
+ LogService logService,
+ PageCacheTracer pageCacheTracer
+ ) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(String storeVersion) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreVersion versionInformation(StoreId storeId) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public RollingUpgradeCompatibility rollingUpgradeCompatibility() {
+ throw new UnsupportedOperationException("5.15 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.15 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.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public List listStorageFiles(FileSystemAbstraction fileSystem, DatabaseLayout databaseLayout) throws
+ IOException {
+ throw new UnsupportedOperationException("5.15 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.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public LogVersionRepository readOnlyLogVersionRepository(
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.15 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.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public StoreId storeId(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.15 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.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public void setExternalStoreUUID(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext,
+ UUID externalStoreId
+ ) throws IOException {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public Optional databaseIdUuid(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.15 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.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public List loadSchemaRules(
+ FileSystemAbstraction fs,
+ PageCache pageCache,
+ Config config,
+ DatabaseLayout databaseLayout,
+ CursorContext cursorContext
+ ) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public StorageFilesState checkStoreFileState(
+ FileSystemAbstraction fs,
+ DatabaseLayout databaseLayout,
+ PageCache pageCache
+ ) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public CommandReaderFactory commandReaderFactory() {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+
+ @Override
+ public DatabaseLayout databaseLayout(Neo4jLayout neo4jLayout, String databaseName) {
+ throw new UnsupportedOperationException("5.15 storage engine requires JDK17");
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/StorageEngineProxyFactoryImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 0000000000..bf1ff69cf5
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java/org/neo4j/gds/compat/_515/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._515;
+
+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.15 storage engine requires JDK17 or later");
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.15";
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryCommandCreationContextImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryCommandCreationContextImpl.java
new file mode 100644
index 0000000000..cb5d914d3e
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryCountsStoreImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryCountsStoreImpl.java
new file mode 100644
index 0000000000..261e63a547
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryCountsStoreImpl.java
@@ -0,0 +1,129 @@
+/*
+ * 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._515;
+
+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.RelationshipType;
+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 estimateNodeCount(int labelId, CursorContext cursorContext) {
+ var label = tokenHolders.labelGetName(labelId);
+ return graphStore.nodes().nodeCount(NodeLabel.of(label));
+ }
+
+ @Override
+ public long relationshipCount(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ // TODO: this is not using start/endLabel
+ if (typeId == -1) {
+ return graphStore.relationshipCount();
+ } else {
+ var type = tokenHolders.relationshipTypeGetName(typeId);
+ return graphStore.relationshipCount(RelationshipType.of(type));
+ }
+ }
+
+ @Override
+ public long estimateRelationshipCount(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ var type = tokenHolders.relationshipTypeGetName(typeId);
+ return graphStore.relationshipCount(RelationshipType.of(type));
+ }
+
+ @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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryMetaDataProviderImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryMetaDataProviderImpl.java
new file mode 100644
index 0000000000..8ec61bacb4
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+import org.neo4j.internal.recordstorage.InMemoryLogVersionRepository515;
+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 InMemoryLogVersionRepository515 logVersionRepository;
+ private final InMemoryTransactionIdStoreImpl transactionIdStore;
+
+ InMemoryMetaDataProviderImpl() {
+ this.logVersionRepository = new InMemoryLogVersionRepository515();
+ 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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryNodeCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryNodeCursor.java
new file mode 100644
index 0000000000..7ab122756e
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryNodeCursor.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._515;
+
+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);
+ }
+
+ @Override
+ public int[] labels() {
+ return intLabels();
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryNodePropertyCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryNodePropertyCursor.java
new file mode 100644
index 0000000000..c4b6a625a1
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryPropertyCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryPropertyCursor.java
new file mode 100644
index 0000000000..2796a80c68
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryPropertySelectionImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryPropertySelectionImpl.java
new file mode 100644
index 0000000000..510cf5b43d
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipPropertyCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipPropertyCursor.java
new file mode 100644
index 0000000000..e8787ca36f
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipScanCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipScanCursor.java
new file mode 100644
index 0000000000..6c9308bc39
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipTraversalCursor.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryRelationshipTraversalCursor.java
new file mode 100644
index 0000000000..a0ab5c5dd2
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineFactory.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineFactory.java
new file mode 100644
index 0000000000..28391b2ec5
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineFactory.java
@@ -0,0 +1,574 @@
+/*
+ * 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._515;
+
+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.InMemoryStorageCommandReaderFactory515;
+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.impl.muninn.VersionStorage;
+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-515";
+
+ public InMemoryStorageEngineFactory() {
+ StorageEngineProxyApi.requireNeo4jVersion(Neo4jVersion.V_5_15, 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,
+ VersionStorage versionStorage
+ ) {
+ 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,
+ LogTailMetadata logTail
+ ) {
+ // 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 InMemoryStorageCommandReaderFactory515.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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineImpl.java
new file mode 100644
index 0000000000..1eac2548c8
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageEngineImpl.java
@@ -0,0 +1,358 @@
+/*
+ * 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._515;
+
+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.InMemoryStorageReader515;
+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(CursorContext cursorContext) {
+ return graphStore.nodeCount();
+ }
+
+ @Override
+ public long relationships(CursorContext cursorContext) {
+ return graphStore.relationshipCount();
+ }
+
+ @Override
+ public long properties(CursorContext cursorContext) {
+ return graphStore.nodePropertyKeys().size() + graphStore.relationshipPropertyKeys().size();
+ }
+
+ @Override
+ public long relationshipTypes(CursorContext cursorContext) {
+ 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 StoreId retrieveStoreId() {
+ return metadataProvider.getStoreId();
+ }
+
+ @Override
+ public StorageEngineIndexingBehaviour indexingBehaviour() {
+ return INDEXING_BEHAVIOUR;
+ }
+
+ @Override
+ public StorageReader newReader() {
+ return new InMemoryStorageReader515(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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageLocksImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStorageLocksImpl.java
new file mode 100644
index 0000000000..b24da4366f
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStoreVersion.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStoreVersion.java
new file mode 100644
index 0000000000..02834c3c6a
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryStoreVersion.java
@@ -0,0 +1,69 @@
+/*
+ * 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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryTransactionIdStoreImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryTransactionIdStoreImpl.java
new file mode 100644
index 0000000000..bd8b3fa9bf
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryVersionCheck.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryVersionCheck.java
new file mode 100644
index 0000000000..deb017b841
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/InMemoryVersionCheck.java
@@ -0,0 +1,72 @@
+/*
+ * 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._515;
+
+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._515.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 StoreVersionIdentifier getCurrentVersion(CursorContext cursorContext) throws
+ IllegalArgumentException, IllegalStateException {
+ return STORE_IDENTIFIER;
+ }
+
+ @Override
+ public boolean isCurrentStoreVersionFullySupported(CursorContext cursorContext) {
+ return true;
+ }
+
+ @Override
+ public boolean isStoreVersionFullySupported(StoreVersionIdentifier storeVersion, CursorContext cursorContext) {
+ return storeVersion.equals(STORE_IDENTIFIER);
+ }
+
+ @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.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/StorageEngineProxyFactoryImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/StorageEngineProxyFactoryImpl.java
new file mode 100644
index 0000000000..acf9f2e9d1
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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_15;
+ }
+
+ @Override
+ public StorageEngineProxyApi load() {
+ return new StorageEngineProxyImpl();
+ }
+
+ @Override
+ public String description() {
+ return "Storage Engine 5.15";
+ }
+}
diff --git a/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/StorageEngineProxyImpl.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/StorageEngineProxyImpl.java
new file mode 100644
index 0000000000..f210c54fb6
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/gds/compat/_515/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._515;
+
+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.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository515.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository515.java
new file mode 100644
index 0000000000..c2c771d2c3
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryLogVersionRepository515.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 InMemoryLogVersionRepository515 implements LogVersionRepository {
+
+ private final AtomicLong logVersion;
+ private final AtomicLong checkpointLogVersion;
+
+ public InMemoryLogVersionRepository515() {
+ this(0, 0);
+ }
+
+ private InMemoryLogVersionRepository515(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.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory515.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory515.java
new file mode 100644
index 0000000000..31ff512ad3
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageCommandReaderFactory515.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 InMemoryStorageCommandReaderFactory515 implements CommandReaderFactory {
+
+ public static final CommandReaderFactory INSTANCE = new InMemoryStorageCommandReaderFactory515();
+
+ @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.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader515.java b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader515.java
new file mode 100644
index 0000000000..251dd31088
--- /dev/null
+++ b/compatibility/5.15/storage-engine-adapter/src/main/java17/org/neo4j/internal/recordstorage/InMemoryStorageReader515.java
@@ -0,0 +1,364 @@
+/*
+ * 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.neo4j.common.EntityType;
+import org.neo4j.common.TokenNameLookup;
+import org.neo4j.counts.CountsStore;
+import org.neo4j.counts.CountsVisitor;
+import org.neo4j.gds.NodeLabel;
+import org.neo4j.gds.RelationshipType;
+import org.neo4j.gds.compat._515.InMemoryNodeCursor;
+import org.neo4j.gds.compat._515.InMemoryPropertyCursor;
+import org.neo4j.gds.compat._515.InMemoryRelationshipScanCursor;
+import org.neo4j.gds.compat._515.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 InMemoryStorageReader515 implements StorageReader {
+
+ protected final CypherGraphStore graphStore;
+ protected final TokenHolders tokenHolders;
+ protected final CountsStore counts;
+ private final Map, Object> dependantState;
+ private boolean closed;
+
+ public InMemoryStorageReader515(
+ CypherGraphStore graphStore,
+ TokenHolders tokenHolders,
+ CountsStore counts
+ ) {
+ this.graphStore = graphStore;
+
+ this.tokenHolders = tokenHolders;
+ this.counts = counts;
+ this.dependantState = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ int[] changedLabels,
+ int[] 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(
+ int[] tokens, int propertyKeyId, EntityType entityType
+ ) {
+ return valueIndexesGetRelated(tokens, new int[]{propertyKeyId}, entityType);
+ }
+
+ @Override
+ public Collection valueIndexesGetRelated(
+ int[] tokens, int[] propertyKeyIds, EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ int[] labels,
+ int propertyKeyId,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public Collection uniquenessConstraintsGetRelated(
+ int[] tokens,
+ int[] propertyKeyIds,
+ EntityType entityType
+ ) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public boolean hasRelatedSchema(int[] 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 new IntSet[0];
+ }
+
+ @Override
+ public Long indexGetOwningUniquenessConstraintId(IndexDescriptor index) {
+ return null;
+ }
+
+ @Override
+ public long countsForNode(int labelId, CursorContext cursorContext) {
+ return counts.nodeCount(labelId, cursorContext);
+ }
+
+ @Override
+ public long estimateCountsForNode(int labelId, CursorContext cursorContext) {
+ return counts.estimateNodeCount(labelId, cursorContext);
+ }
+
+ @Override
+ public long countsForRelationship(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ return counts.relationshipCount(startLabelId, typeId, endLabelId, cursorContext);
+ }
+
+ @Override
+ public void visitAllCounts(CountsVisitor countsVisitor, CursorContext cursorContext) {
+ for (NodeLabel label : graphStore.nodeLabels()) {
+ var tokenHolder = tokenHolders.labelTokens();
+ countsVisitor.visitNodeCount(tokenHolder.getIdByName(label.name()), graphStore.nodes().nodeCount(label));
+ }
+
+ for (RelationshipType relationshipType : graphStore.relationshipTypes()) {
+ var tokenHolder = tokenHolders.relationshipTypeTokens();
+ // we dont know start / end label for a reltype
+ countsVisitor.visitRelationshipCount(
+ -1,
+ tokenHolder.getIdByName(relationshipType.name()),
+ -1,
+ graphStore.relationshipCount(relationshipType)
+ );
+ }
+ }
+
+ @Override
+ public long estimateCountsForRelationship(int startLabelId, int typeId, int endLabelId, CursorContext cursorContext) {
+ return counts.estimateRelationshipCount(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/doc/modules/ROOT/pages/installation/supported-neo4j-versions.adoc b/doc/modules/ROOT/pages/installation/supported-neo4j-versions.adoc
index 696c562e16..b1102adaf2 100644
--- a/doc/modules/ROOT/pages/installation/supported-neo4j-versions.adoc
+++ b/doc/modules/ROOT/pages/installation/supported-neo4j-versions.adoc
@@ -10,6 +10,7 @@ If your version of GDS or Neo4j is not listed in the matrix, you should upgrade.
[opts=header]
|===
| Neo4j version | Neo4j Graph Data Science
+| `5.15` | `2.6`, `2.5.6` or later
| `5.14` | `2.6`, `2.5.5` or later
| `5.13` | `2.6`, `2.5.1` or later
| `5.12` | `2.6`, `2.5`
diff --git a/neo4j-adapter/src/main/java/org/neo4j/gds/compat/Neo4jVersion.java b/neo4j-adapter/src/main/java/org/neo4j/gds/compat/Neo4jVersion.java
index 44a08f4095..722a0d15ed 100644
--- a/neo4j-adapter/src/main/java/org/neo4j/gds/compat/Neo4jVersion.java
+++ b/neo4j-adapter/src/main/java/org/neo4j/gds/compat/Neo4jVersion.java
@@ -42,9 +42,10 @@ public enum Neo4jVersion {
V_5_12,
V_5_13,
V_5_14,
+ V_5_15,
V_Dev;
- private static final int MINOR_DEV_VERSION = 15;
+ private static final int MINOR_DEV_VERSION = 16;
static Neo4jVersion parse(String version) {
var versionSegments = Pattern.compile("[.-]")
@@ -87,6 +88,8 @@ static Neo4jVersion parse(String version) {
return Neo4jVersion.V_5_13;
case 14:
return Neo4jVersion.V_5_14;
+ case 15:
+ return Neo4jVersion.V_5_15;
default:
if (minorVersion >= MINOR_DEV_VERSION) {
return Neo4jVersion.V_Dev;
@@ -163,6 +166,8 @@ public String toString() {
return "5.13";
case V_5_14:
return "5.14";
+ case V_5_15:
+ return "5.15";
case V_Dev:
return "dev";
default:
diff --git a/neo4j-adapter/src/test/java/org/neo4j/gds/compat/Neo4jVersionTest.java b/neo4j-adapter/src/test/java/org/neo4j/gds/compat/Neo4jVersionTest.java
index 81019201d8..4376026a84 100644
--- a/neo4j-adapter/src/test/java/org/neo4j/gds/compat/Neo4jVersionTest.java
+++ b/neo4j-adapter/src/test/java/org/neo4j/gds/compat/Neo4jVersionTest.java
@@ -49,7 +49,8 @@ class Neo4jVersionTest {
"5.12.0, V_5_12",
"5.13.0, V_5_13",
"5.14.0, V_5_14",
- "5.15.0, V_Dev",
+ "5.15.0, V_5_15",
+ "5.16.0, V_Dev",
})
void testParse(String input, Neo4jVersion expected) {
assertEquals(expected.name(), Neo4jVersion.parse(input).name());
diff --git a/proc/sysinfo/src/test/java/org/neo4j/gds/SysInfoProcTest.java b/proc/sysinfo/src/test/java/org/neo4j/gds/SysInfoProcTest.java
index b11fb9657c..c8eefd42c5 100644
--- a/proc/sysinfo/src/test/java/org/neo4j/gds/SysInfoProcTest.java
+++ b/proc/sysinfo/src/test/java/org/neo4j/gds/SysInfoProcTest.java
@@ -84,6 +84,9 @@ class SysInfoProcTest extends BaseProcTest {
"Neo4j 5.14",
"Neo4j 5.14 (placeholder)",
+ "Neo4j 5.15",
+ "Neo4j 5.15 (placeholder)",
+
"Neo4j DEV",
"Neo4j DEV (placeholder)",
@@ -212,6 +215,14 @@ void testSysInfoProc() throws IOException {
"Neo4j 5.14"
);
break;
+ case V_5_15:
+ expectedCompatibilities = Set.of(
+ "Neo4j Settings 5.x (placeholder)",
+ "Neo4j Settings 5.x",
+ "Neo4j 5.15 (placeholder)",
+ "Neo4j 5.15"
+ );
+ break;
case V_Dev:
expectedCompatibilities = Set.of(
"Neo4j Settings 5.x",
diff --git a/settings.gradle b/settings.gradle
index 3185cbc7eb..78b72b02f0 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -322,3 +322,8 @@ project(':open-write-services').projectDir = file('open-write-services')
include('defaults-and-limits-configuration')
project(':defaults-and-limits-configuration').projectDir = file('defaults-and-limits-configuration')
+
+include('neo4j-kernel-adapter-5.15')
+project(':neo4j-kernel-adapter-5.15').projectDir = file('compatibility/5.15/neo4j-kernel-adapter')
+include('storage-engine-adapter-5.15')
+project(':storage-engine-adapter-5.15').projectDir = file('compatibility/5.15/storage-engine-adapter')