From f17e74037990a2685d174d4a392ea208644da1f1 Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Thu, 1 Feb 2018 09:08:13 +0100 Subject: [PATCH] Use Kernel API for index seek in compiled runtime --- .../internal/codegen/CompiledIndexUtils.java | 34 ++++++---- .../codegen/CompiledIndexUtilsTest.java | 44 ++++++------ .../interpreted/DelegatingQueryContext.scala | 2 + .../TransactionalContextWrapper.scala | 4 +- .../internal/runtime/QueryContext.scala | 2 + .../kernel/api/NodeValueIndexCursor.java | 68 +++++++++++++++++++ .../compiled/codegen/ir/IndexSeek.scala | 6 +- .../codegen/spi/MethodStructure.scala | 7 +- .../internal/spi/v3_4/codegen/Fields.scala | 3 +- .../codegen/GeneratedMethodStructure.scala | 52 +++++++++----- .../codegen/GeneratedQueryStructure.scala | 4 +- .../internal/spi/v3_4/codegen/Templates.scala | 15 ++++ .../v3_4/GeneratedMethodStructureTest.scala | 4 +- 13 files changed, 181 insertions(+), 64 deletions(-) diff --git a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtils.java b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtils.java index 955ae53d0d059..719acb1933b29 100644 --- a/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtils.java +++ b/community/cypher/cypher/src/main/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtils.java @@ -19,12 +19,13 @@ */ package org.neo4j.cypher.internal.codegen; -import org.neo4j.collection.primitive.PrimitiveLongCollections; -import org.neo4j.collection.primitive.PrimitiveLongIterator; -import org.neo4j.kernel.api.ReadOperations; -import org.neo4j.kernel.api.exceptions.index.IndexNotApplicableKernelException; -import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; -import org.neo4j.kernel.api.schema.index.IndexDescriptor; +import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.CursorFactory; +import org.neo4j.internal.kernel.api.IndexOrder; +import org.neo4j.internal.kernel.api.IndexQuery; +import org.neo4j.internal.kernel.api.NodeValueIndexCursor; +import org.neo4j.internal.kernel.api.Read; +import org.neo4j.internal.kernel.api.exceptions.KernelException; import static org.neo4j.cypher.internal.codegen.CompiledConversionUtils.makeValueNeoSafe; import static org.neo4j.internal.kernel.api.IndexQuery.exact; @@ -45,23 +46,26 @@ private CompiledIndexUtils() /** * Performs an index seek. * - * @param readOperations The ReadOperation instance to use for seeking - * @param descriptor The descriptor of the index - * @param propertyId The property to seek for + * @param read The Read instance to use for seeking + * @param cursors Used for cursor allocation + * @param index A reference to an index * @param value The value to seek for - * @return An iterator containing data found in index. + * @return A cursor positioned at the data found in index. */ - public static PrimitiveLongIterator indexSeek( ReadOperations readOperations, IndexDescriptor descriptor, - int propertyId, Object value ) - throws IndexNotApplicableKernelException, IndexNotFoundKernelException + public static NodeValueIndexCursor indexSeek( Read read, CursorFactory cursors, CapableIndexReference index, Object value ) + throws KernelException { + assert index.properties().length == 1; if ( value == null ) { - return PrimitiveLongCollections.emptyIterator(); + return NodeValueIndexCursor.EMPTY; } else { - return readOperations.indexQuery( descriptor, exact( propertyId, makeValueNeoSafe( value ) ) ); + NodeValueIndexCursor cursor = cursors.allocateNodeValueIndexCursor(); + IndexQuery.ExactPredicate query = exact( index.properties()[0], makeValueNeoSafe( value ) ); + read.nodeIndexSeek( index, cursor, IndexOrder.NONE, query ); + return cursor; } } } diff --git a/community/cypher/cypher/src/test/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtilsTest.java b/community/cypher/cypher/src/test/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtilsTest.java index fe1f6a9085d84..7c82b825bc290 100644 --- a/community/cypher/cypher/src/test/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtilsTest.java +++ b/community/cypher/cypher/src/test/java/org/neo4j/cypher/internal/codegen/CompiledIndexUtilsTest.java @@ -21,13 +21,11 @@ import org.junit.Test; -import org.neo4j.collection.primitive.PrimitiveLongIterator; -import org.neo4j.kernel.api.ReadOperations; -import org.neo4j.kernel.api.exceptions.EntityNotFoundException; -import org.neo4j.kernel.api.exceptions.index.IndexNotApplicableKernelException; -import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; -import org.neo4j.kernel.api.schema.index.IndexDescriptor; -import org.neo4j.kernel.api.schema.index.IndexDescriptorFactory; +import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.CursorFactory; +import org.neo4j.internal.kernel.api.NodeValueIndexCursor; +import org.neo4j.internal.kernel.api.Read; +import org.neo4j.internal.kernel.api.exceptions.KernelException; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; @@ -35,39 +33,41 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.neo4j.kernel.api.index.IndexQueryHelper.exact; +import static org.mockito.Mockito.when; public class CompiledIndexUtilsTest { + @Test - public void shouldCallIndexSeek() - throws EntityNotFoundException, IndexNotApplicableKernelException, IndexNotFoundKernelException + public void shouldCallIndexSeek() throws KernelException { + // GIVEN - ReadOperations read = mock( ReadOperations.class ); + Read read = mock( Read.class ); + CapableIndexReference index = mock( CapableIndexReference.class ); + when( index.properties() ).thenReturn( new int[]{42} ); // WHEN - IndexDescriptor descriptor = IndexDescriptorFactory.forLabel( 12, 42 ); - CompiledIndexUtils.indexSeek( read, descriptor, 42, "hello" ); + CompiledIndexUtils.indexSeek( read, mock( CursorFactory.class ), index, "hello" ); // THEN - verify( read, times( 1 ) ).indexQuery( descriptor, exact( 42, "hello" ) ); + verify( read, times( 1 ) ).nodeIndexSeek( any(), any(), any(), any() ); } @Test - public void shouldHandleNullInIndexSeek() - throws EntityNotFoundException, IndexNotApplicableKernelException, IndexNotFoundKernelException + public void shouldHandleNullInIndexSeek() throws KernelException { // GIVEN - ReadOperations read = mock( ReadOperations.class ); + Read read = mock( Read.class ); + CapableIndexReference index = mock( CapableIndexReference.class ); + when( index.properties() ).thenReturn( new int[]{42} ); // WHEN - IndexDescriptor descriptor = IndexDescriptorFactory.forLabel( 12, 42 ); - PrimitiveLongIterator iterator = - CompiledIndexUtils.indexSeek( read, descriptor, 42, null ); + NodeValueIndexCursor cursor = CompiledIndexUtils.indexSeek( mock( Read.class ), mock( CursorFactory.class ), + index, null ); // THEN - verify( read, never() ).indexQuery( any( ), any( ) ); - assertFalse( iterator.hasNext() ); + verify( read, never() ).nodeIndexSeek( any(), any(), any() ); + assertFalse( cursor.next() ); } } diff --git a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/DelegatingQueryContext.scala b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/DelegatingQueryContext.scala index 8dd90ecd9d3c1..748f3d92d1406 100644 --- a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/DelegatingQueryContext.scala +++ b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/DelegatingQueryContext.scala @@ -300,5 +300,7 @@ class DelegatingQueryTransactionalContext(val inner: QueryTransactionalContext) override def tokenRead: TokenRead = inner.tokenRead + override def schemaRead: SchemaRead = inner.schemaRead + override def dataWrite: Write = inner.dataWrite } diff --git a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionalContextWrapper.scala b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionalContextWrapper.scala index 8a50b17c034fd..c08bc0fb74b42 100644 --- a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionalContextWrapper.scala +++ b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionalContextWrapper.scala @@ -22,8 +22,8 @@ package org.neo4j.cypher.internal.runtime.interpreted import org.neo4j.cypher.internal.planner.v3_4.spi.KernelStatisticProvider import org.neo4j.cypher.internal.runtime.QueryTransactionalContext import org.neo4j.graphdb.{Lock, PropertyContainer} +import org.neo4j.internal.kernel.api._ import org.neo4j.internal.kernel.api.security.SecurityContext -import org.neo4j.internal.kernel.api.{CursorFactory, Read, TokenRead, Write} import org.neo4j.kernel.GraphDatabaseQueryService import org.neo4j.kernel.api.KernelTransaction.Revertable import org.neo4j.kernel.api.dbms.DbmsOperations @@ -59,6 +59,8 @@ case class TransactionalContextWrapper(tc: TransactionalContext) extends QueryTr override def tokenRead: TokenRead = tc.kernelTransaction().tokenRead() + override def schemaRead: SchemaRead = tc.kernelTransaction().schemaRead() + override def dataWrite: Write = tc.kernelTransaction().dataWrite() override def readOperations: ReadOperations = tc.readOperations() diff --git a/community/cypher/runtime-util/src/main/scala/org/neo4j/cypher/internal/runtime/QueryContext.scala b/community/cypher/runtime-util/src/main/scala/org/neo4j/cypher/internal/runtime/QueryContext.scala index a07372ba963b6..648d8542fcb77 100644 --- a/community/cypher/runtime-util/src/main/scala/org/neo4j/cypher/internal/runtime/QueryContext.scala +++ b/community/cypher/runtime-util/src/main/scala/org/neo4j/cypher/internal/runtime/QueryContext.scala @@ -246,6 +246,8 @@ trait QueryTransactionalContext extends CloseableResource { def tokenRead: TokenRead + def schemaRead: SchemaRead + def dataWrite: Write def readOperations: ReadOperations diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/NodeValueIndexCursor.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/NodeValueIndexCursor.java index df4405a7c7e77..719f8c02b7f54 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/NodeValueIndexCursor.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/NodeValueIndexCursor.java @@ -21,6 +21,8 @@ import org.neo4j.values.storable.Value; +import static org.neo4j.values.storable.Values.NO_VALUE; + /** * Cursor for scanning the property values of nodes in a schema index. *

@@ -65,4 +67,70 @@ public interface NodeValueIndexCursor extends NodeIndexCursor boolean hasValue(); Value propertyValue( int offset ); + + class Empty implements NodeValueIndexCursor + { + + @Override + public void node( NodeCursor cursor ) + { + + } + + @Override + public long nodeReference() + { + return -1L; + } + + @Override + public boolean next() + { + return false; + } + + @Override + public boolean shouldRetry() + { + return false; + } + + @Override + public void close() + { + + } + + @Override + public boolean isClosed() + { + return false; + } + + @Override + public int numberOfProperties() + { + return 0; + } + + @Override + public int propertyKey( int offset ) + { + return -1; + } + + @Override + public boolean hasValue() + { + return false; + } + + @Override + public Value propertyValue( int offset ) + { + return NO_VALUE; + } + } + + NodeValueIndexCursor EMPTY = new Empty(); } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/ir/IndexSeek.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/ir/IndexSeek.scala index 349d6cd5597bd..cb6e3b1dea6e4 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/ir/IndexSeek.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/ir/IndexSeek.scala @@ -33,7 +33,7 @@ case class IndexSeek(opName: String, labelName: String, propNames: Seq[String], val propKeyVar = context.namer.newVarName() generator.lookupLabelId(labelVar, labelName) generator.lookupPropertyKey(propNames.head, propKeyVar) - generator.newIndexDescriptor(descriptorVar, labelVar, propKeyVar) + generator.newIndexReference(descriptorVar, labelVar, propKeyVar) } override def produceIterator[E](iterVar: String, generator: MethodStructure[E])(implicit context: CodeGenContext) = { @@ -44,8 +44,8 @@ case class IndexSeek(opName: String, labelName: String, propNames: Seq[String], override def produceNext[E](nextVar: Variable, iterVar: String, generator: MethodStructure[E]) (implicit context: CodeGenContext) = { generator.incrementDbHits() - generator.nextNode(nextVar.name, iterVar) + generator.nodeFromNodeValueIndexCursor(nextVar.name, iterVar) } - override def hasNext[E](generator: MethodStructure[E], iterVar: String): E = generator.hasNextNode(iterVar) + override def hasNext[E](generator: MethodStructure[E], iterVar: String): E = generator.advanceNodeValueIndexCursor(iterVar) } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/spi/MethodStructure.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/spi/MethodStructure.scala index 814565417547f..567e7b6d331eb 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/spi/MethodStructure.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/compiled/codegen/spi/MethodStructure.scala @@ -158,7 +158,7 @@ trait MethodStructure[E] { def nodeGetRelationshipsWithDirectionAndTypes(iterVar: String, nodeVar: String, nodeVarType: CodeGenType, direction: SemanticDirection, typeVars: Seq[String]): Unit def connectingRelationships(iterVar: String, fromNode: String, fromNodeType: CodeGenType, dir: SemanticDirection, toNode:String, toNodeType: CodeGenType) def connectingRelationships(iterVar: String, fromNode: String, fromNodeType: CodeGenType, dir: SemanticDirection, types: Seq[String], toNode: String, toNodeType: CodeGenType) - def nextNode(targetVar: String, iterVar: String): Unit + def nodeFromNodeValueIndexCursor(targetVar: String, iterVar: String): Unit def nodeFromNodeCursor(targetVar: String, iterVar: String): Unit def nodeFromNodeLabelIndexCursor(targetVar: String, iterVar: String): Unit def nextRelationshipAndNode(toNodeVar: String, iterVar: String, direction: SemanticDirection, fromNodeVar: String, relVar: String): Unit @@ -167,6 +167,8 @@ trait MethodStructure[E] { def advanceNodeCursor(iterVar: String): E def advanceNodeLabelIndexCursor(iterVar: String): E def advanceRelationshipSelectionCursor(iterVar: String): E + def advanceNodeValueIndexCursor(iterVar: String): E + def hasNextRelationship(iterVar: String): E def nodeGetPropertyById(nodeVar: String, nodeVarType: CodeGenType, propId: Int, propValueVar: String): Unit def nodeGetPropertyForVar(nodeVar: String, nodeVarType: CodeGenType, propIdVar: String, propValueVar: String): Unit def nodeIdSeek(nodeIdVar: String, expression: E, codeGenType: CodeGenType)(block: MethodStructure[E] => Unit): Unit @@ -175,7 +177,8 @@ trait MethodStructure[E] { def lookupPropertyKey(propName: String, propVar: String) def indexSeek(iterVar: String, descriptorVar: String, value: E, codeGenType: CodeGenType): Unit def relType(relIdVar: String, typeVar: String): Unit - def newIndexDescriptor(descriptorVar: String, labelVar: String, propKeyVar: String): Unit + def newIndexReference(descriptorVar: String, labelVar: String, propKeyVar: String): Unit + def createRelExtractor(extractorName: String): Unit def nodeCountFromCountStore(expression: E): E def relCountFromCountStore(start: E, end: E, types: E*): E def token(t: Int): E diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Fields.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Fields.scala index 787687358281d..7e7fb59441735 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Fields.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Fields.scala @@ -35,5 +35,6 @@ case class Fields(closer: FieldReference, nodeCursor: FieldReference, propertyCursor: FieldReference, dataRead: FieldReference, - tokenRead: FieldReference + tokenRead: FieldReference, + schemaRead: FieldReference ) diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedMethodStructure.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedMethodStructure.scala index 8018570e95954..c9714c07ed01b 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedMethodStructure.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedMethodStructure.scala @@ -44,9 +44,7 @@ import org.neo4j.cypher.internal.v3_4.expressions.SemanticDirection import org.neo4j.graphdb.{Direction, Node, Relationship} import org.neo4j.internal.kernel.api._ import org.neo4j.internal.kernel.api.helpers.RelationshipSelectionCursor -import org.neo4j.internal.kernel.api.schema.LabelSchemaDescriptor import org.neo4j.kernel.api.ReadOperations -import org.neo4j.kernel.api.schema.index.{IndexDescriptor, IndexDescriptorFactory} import org.neo4j.kernel.impl.util.ValueUtils import org.neo4j.values.AnyValue import org.neo4j.values.storable._ @@ -111,8 +109,9 @@ class GeneratedMethodStructure(val fields: Fields, val generator: CodeBlock, aux HashTable(valueType, listType, tableType, get, put, add) } - override def nextNode(targetVar: String, iterVar: String) = - generator.assign(typeRef[Long], targetVar, invoke(generator.load(iterVar), nextLong)) + override def nodeFromNodeValueIndexCursor(targetVar: String, iterVar: String) = + generator.assign(typeRef[Long], targetVar, invoke(generator.load(iterVar), + method[NodeValueIndexCursor, Long]("nodeReference"))) override def nodeFromNodeCursor(targetVar: String, iterVar: String) = generator.assign(typeRef[Long], targetVar, invoke(generator.load(iterVar), method[NodeCursor, Long]("nodeReference"))) @@ -177,9 +176,17 @@ class GeneratedMethodStructure(val fields: Fields, val generator: CodeBlock, aux override def advanceNodeLabelIndexCursor(iterVar: String) = invoke(generator.load(iterVar), method[NodeLabelIndexCursor, Boolean]("next")) +<<<<<<< HEAD override def advanceRelationshipSelectionCursor(iterVar: String) = invoke(generator.load(iterVar), method[RelationshipSelectionCursor, Boolean]("next")) +======= + override def advanceNodeValueIndexCursor(iterVar: String) = + invoke(generator.load(iterVar), method[NodeValueIndexCursor, Boolean]("next")) + + override def hasNextRelationship(iterVar: String) = + invoke(generator.load(iterVar), hasMoreRelationship) +>>>>>>> Use Kernel API for index seek in compiled runtime override def whileLoop(test: Expression)(block: MethodStructure[Expression] => Unit) = using(generator.whileLoop(test)) { body => @@ -554,6 +561,9 @@ class GeneratedMethodStructure(val fields: Fields, val generator: CodeBlock, aux private def tokenRead: Expression = invoke(generator.self(), methodReference(generator.owner(), typeRef[TokenRead], "getOrLoadTokenRead")) + private def schemaRead: Expression = + invoke(generator.self(), methodReference(generator.owner(), typeRef[SchemaRead], "getOrLoadSchemaRead")) + private def cursors: Expression = invoke(generator.self(), methodReference(generator.owner(), typeRef[CursorFactory], "getOrLoadCursors")) @@ -1474,27 +1484,33 @@ class GeneratedMethodStructure(val fields: Fields, val generator: CodeBlock, aux override def lookupPropertyKey(propName: String, propIdVar: String) = generator.assign(typeRef[Int], propIdVar, invoke(tokenRead, propertyKeyGetForName, constant(propName))) - override def newIndexDescriptor(descriptorVar: String, labelVar: String, propKeyVar: String) = { - val getIndexDescriptor = method[IndexDescriptorFactory, IndexDescriptor]("forLabel", typeRef[Int], typeRef[Array[Int]]) + override def newIndexReference(referenceVar: String, labelVar: String, propKeyVar: String) = { val propertyIdsExpr = Expression.newArray(typeRef[Int], generator.load(propKeyVar)) - generator.assign(typeRef[IndexDescriptor], descriptorVar, - invoke(getIndexDescriptor, generator.load(labelVar), propertyIdsExpr )) + + generator.assign(typeRef[CapableIndexReference], referenceVar, + invoke(schemaRead, + method[SchemaRead, CapableIndexReference]("index", typeRef[Int], typeRef[Array[Int]]), + generator.load(labelVar), propertyIdsExpr) + ) } - override def indexSeek(iterVar: String, descriptorVar: String, value: Expression, codeGenType: CodeGenType) = { - val local = generator.declare(typeRef[PrimitiveLongIterator], iterVar) + override def indexSeek(iterVar: String, indexReference: String, value: Expression, codeGenType: CodeGenType) = { + val local = generator.declare(typeRef[NodeValueIndexCursor], iterVar) + generator.assign(local, constant(null)) + _finalizers.append((_: Boolean) => (block) => + using(block.ifStatement(Expression.notNull(block.load(iterVar)))) { inner => + inner.expression( + invoke(block.load(iterVar), method[NodeValueIndexCursor, Unit]("close"))) + }) val boxedValue = - if (codeGenType.isPrimitive) Expression.box(value) - else invoke(methodReference(typeRef[CompiledConversionUtils], typeRef[Object], "makeValueNeoSafe", typeRef[Object]), value) + if (codeGenType.isPrimitive) Expression.box(value) else value handleKernelExceptions(generator, fields, _finalizers) { body => - val descriptor = body.load(descriptorVar) - val schema = invoke(descriptor, method[IndexDescriptor, LabelSchemaDescriptor]("schema")) - val propertyKeyId = invoke(schema, method[LabelSchemaDescriptor, Int]("getPropertyId")) + val index = body.load(indexReference) body.assign(local, invoke( - methodReference(typeRef[CompiledIndexUtils], typeRef[PrimitiveLongIterator], "indexSeek", - typeRef[ReadOperations], typeRef[IndexDescriptor], typeRef[Int], typeRef[AnyRef]), - readOperations, descriptor, propertyKeyId, boxedValue) + methodReference(typeRef[CompiledIndexUtils], typeRef[NodeValueIndexCursor], "indexSeek", + typeRef[Read], typeRef[CursorFactory], typeRef[CapableIndexReference], typeRef[AnyRef]), + dataRead, cursors, index, boxedValue) ) } } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedQueryStructure.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedQueryStructure.scala index d9f3ca7578cc1..7b7890366267b 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedQueryStructure.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/GeneratedQueryStructure.scala @@ -181,6 +181,7 @@ object GeneratedQueryStructure extends CodeStructure[GeneratedQuery] { Templates.getOrLoadReadOperations(clazz, fields) Templates.getOrLoadDataRead(clazz, fields) Templates.getOrLoadTokenRead(clazz, fields) + Templates.getOrLoadSchemaRead(clazz, fields) Templates.getOrLoadCursors(clazz, fields) Templates.nodeCursor(clazz, fields) Templates.propertyCursor(clazz, fields) @@ -216,7 +217,8 @@ object GeneratedQueryStructure extends CodeStructure[GeneratedQuery] { nodeCursor = clazz.field(typeRef[NodeCursor], "nodeCursor"), propertyCursor = clazz.field(typeRef[PropertyCursor], "propertyCursor"), dataRead = clazz.field(typeRef[Read], "dataRead"), - tokenRead = clazz.field(typeRef[TokenRead], "tokenRead") + tokenRead = clazz.field(typeRef[TokenRead], "tokenRead"), + schemaRead = clazz.field(typeRef[SchemaRead], "schemaRead") ) } diff --git a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Templates.scala b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Templates.scala index 915d199498bad..fbbe57ac5ee7c 100644 --- a/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Templates.scala +++ b/enterprise/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_4/codegen/Templates.scala @@ -262,6 +262,21 @@ object Templates { } } + def getOrLoadSchemaRead(clazz: ClassGenerator, fields: Fields) = { + val methodBuilder: Builder = MethodDeclaration.method(typeRef[SchemaRead], "getOrLoadSchemaRead") + using(clazz.generate(methodBuilder)) { generate => + val schemaRead = Expression.get(generate.self(), fields.schemaRead) + using(generate.ifStatement(Expression.isNull(schemaRead))) { block => + val transactionalContext: MethodReference = method[QueryContext, QueryTransactionalContext]("transactionalContext") + val schemaRead: MethodReference = method[QueryTransactionalContext, SchemaRead]("schemaRead") + val queryContext = Expression.get(block.self(), fields.queryContext) + block.put(block.self(), fields.schemaRead, + Expression.invoke(Expression.invoke(queryContext, transactionalContext), schemaRead)) + } + generate.returns(schemaRead) + } + } + def setCompletable(classHandle: ClassHandle) = MethodTemplate.method(typeRef[Unit], "setCompletable", param[Completable]("closeable")). put(self(classHandle), typeRef[Completable], "closeable", load("closeable", typeRef[Completable])). diff --git a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/spi/v3_4/GeneratedMethodStructureTest.scala b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/spi/v3_4/GeneratedMethodStructureTest.scala index 6e03544b9ff07..dcfafd63125b6 100644 --- a/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/spi/v3_4/GeneratedMethodStructureTest.scala +++ b/enterprise/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compiled_runtime/spi/v3_4/GeneratedMethodStructureTest.scala @@ -246,7 +246,8 @@ class GeneratedMethodStructureTest extends CypherFunSuite { nodeCursor = body.field(typeRef[NodeCursor], "nodeCursor"), propertyCursor = body.field(typeRef[PropertyCursor], "propertyCursor"), dataRead = body.field(typeRef[Read], "dataRead"), - tokenRead = body.field(typeRef[TokenRead], "tokenRead") + tokenRead = body.field(typeRef[TokenRead], "tokenRead"), + schemaRead = body.field(typeRef[SchemaRead], "schemaRead") ) // the "COLUMNS" static field body.staticField(typeRef[util.List[String]], "COLUMNS", Templates.asList[String](Seq.empty)) @@ -257,6 +258,7 @@ class GeneratedMethodStructureTest extends CypherFunSuite { Templates.getOrLoadReadOperations(body, fields) Templates.getOrLoadCursors(body, fields) Templates.getOrLoadTokenRead(body, fields) + Templates.getOrLoadSchemaRead(body, fields) Templates.nodeCursor(body, fields) Templates.propertyCursor(body, fields) body.handle()