Skip to content

Commit

Permalink
Set needsValue conditionally in NodeValueCursor
Browse files Browse the repository at this point in the history
The `DefaultNodeValueIndexCursor` would alwazs (when possible)
set `needsValue` to true and deserialize values even if the caller
of the index operation did not need the property values.

Now, the caller (e.g. NodeIndexSeeker) decides whether values are
needed.

Adds parametrized tests in `NodeTransactionStateTestBase` to hit
both code paths when values and needed and when not.
  • Loading branch information
sherfert committed Aug 14, 2018
1 parent cb2edb9 commit c5d93db
Show file tree
Hide file tree
Showing 49 changed files with 471 additions and 322 deletions.
Expand Up @@ -85,8 +85,7 @@ public void shouldNotAllowConcurrentViolationOfConstraint() throws Exception
Read read = ktx.dataRead(); Read read = ktx.dataRead();
try ( NodeValueIndexCursor cursor = ktx.cursors().allocateNodeValueIndexCursor() ) try ( NodeValueIndexCursor cursor = ktx.cursors().allocateNodeValueIndexCursor() )
{ {
read.nodeIndexSeek( ktx.schemaRead().index( labelId, propertyKeyId ), cursor, IndexOrder.NONE, read.nodeIndexSeek( ktx.schemaRead().index( labelId, propertyKeyId ), cursor, IndexOrder.NONE, false, IndexQuery.exact( index.schema().getPropertyId(),
IndexQuery.exact( index.schema().getPropertyId(),
"The value is irrelevant, we just want to perform some sort of lookup against this " + "The value is irrelevant, we just want to perform some sort of lookup against this " +
"index" ) ); "index" ) );
} }
Expand Down
Expand Up @@ -824,7 +824,7 @@ void assertSameContent( List<Long> actual, List<Long> expected )
NodeValueIndexCursor indexQuery( KernelTransaction ktx, IndexDescriptor indexDescriptor, IndexQuery... indexQueries ) throws KernelException NodeValueIndexCursor indexQuery( KernelTransaction ktx, IndexDescriptor indexDescriptor, IndexQuery... indexQueries ) throws KernelException
{ {
NodeValueIndexCursor cursor = ktx.cursors().allocateNodeValueIndexCursor(); NodeValueIndexCursor cursor = ktx.cursors().allocateNodeValueIndexCursor();
ktx.dataRead().nodeIndexSeek( indexDescriptor, cursor, IndexOrder.NONE, indexQueries ); ktx.dataRead().nodeIndexSeek( indexDescriptor, cursor, IndexOrder.NONE, false, indexQueries );
return cursor; return cursor;
} }
} }
Expand Down
Expand Up @@ -155,8 +155,7 @@ public void shouldHandleCompositeSizesCloseToTheLimit() throws KernelException
{ {
ktx.dataRead().nodeIndexSeek( TestIndexDescriptorFactory ktx.dataRead().nodeIndexSeek( TestIndexDescriptorFactory
.forLabel( labelId, propertyKeyId1, propertyKeyId2 ), .forLabel( labelId, propertyKeyId1, propertyKeyId2 ),
cursor, IndexOrder.NONE, cursor, IndexOrder.NONE, false, IndexQuery.exact( propertyKeyId1, string1 ),
IndexQuery.exact( propertyKeyId1, string1 ),
IndexQuery.exact( propertyKeyId2, string2 ) ); IndexQuery.exact( propertyKeyId2, string2 ) );
assertTrue( cursor.next() ); assertTrue( cursor.next() );
assertEquals( node.getId(), cursor.nodeReference() ); assertEquals( node.getId(), cursor.nodeReference() );
Expand Down
Expand Up @@ -50,4 +50,16 @@ protected boolean spatialRangeSupport()
{ {
return true; return true;
} }

@Override
protected boolean indexProvidesStringValues()
{
return false;
}

@Override
protected boolean indexProvidesNumericValues()
{
return false;
}
} }
Expand Up @@ -48,4 +48,16 @@ protected boolean spatialRangeSupport()
{ {
return true; return true;
} }

@Override
protected boolean indexProvidesStringValues()
{
return false;
}

@Override
protected boolean indexProvidesNumericValues()
{
return true;
}
} }
Expand Up @@ -48,4 +48,16 @@ protected boolean spatialRangeSupport()
{ {
return true; return true;
} }

@Override
protected boolean indexProvidesStringValues()
{
return true;
}

@Override
protected boolean indexProvidesNumericValues()
{
return true;
}
} }
Expand Up @@ -337,7 +337,7 @@ private long createNode()
private NodeValueIndexCursor seek( KernelTransaction transaction ) throws KernelException private NodeValueIndexCursor seek( KernelTransaction transaction ) throws KernelException
{ {
NodeValueIndexCursor cursor = transaction.cursors().allocateNodeValueIndexCursor(); NodeValueIndexCursor cursor = transaction.cursors().allocateNodeValueIndexCursor();
transaction.dataRead().nodeIndexSeek( index, cursor, IndexOrder.NONE, exactQuery() ); transaction.dataRead().nodeIndexSeek( index, cursor, IndexOrder.NONE, false, exactQuery() );
return cursor; return cursor;
} }


Expand Down
Expand Up @@ -201,7 +201,7 @@ public void shouldPopulateAndUpdate() throws Exception
for ( NodeAndValue entry : Iterables.concat( valueSet1, valueSet2 ) ) for ( NodeAndValue entry : Iterables.concat( valueSet1, valueSet2 ) )
{ {
NodeValueIterator nodes = new NodeValueIterator(); NodeValueIterator nodes = new NodeValueIterator();
reader.query( nodes, IndexOrder.NONE, IndexQuery.exact( propertyKeyId, entry.value ) ); reader.query( nodes, IndexOrder.NONE, false , IndexQuery.exact( propertyKeyId, entry.value ) );
assertEquals( entry.nodeId, nodes.next() ); assertEquals( entry.nodeId, nodes.next() );
assertFalse( nodes.hasNext() ); assertFalse( nodes.hasNext() );
} }
Expand Down Expand Up @@ -231,7 +231,7 @@ private void assertHasAllValues( List<NodeAndValue> values ) throws IOException,
for ( NodeAndValue entry : values ) for ( NodeAndValue entry : values )
{ {
NodeValueIterator nodes = new NodeValueIterator(); NodeValueIterator nodes = new NodeValueIterator();
reader.query( nodes, IndexOrder.NONE, IndexQuery.exact( propertyKeyId, entry.value ) ); reader.query( nodes, IndexOrder.NONE, false, IndexQuery.exact( propertyKeyId, entry.value ) );
assertEquals( entry.nodeId, nodes.next() ); assertEquals( entry.nodeId, nodes.next() );
assertFalse( nodes.hasNext() ); assertFalse( nodes.hasNext() );
} }
Expand Down Expand Up @@ -267,7 +267,7 @@ public void shouldProvidePopulatorThatAcceptsDuplicateEntries() throws Exception
for ( NodeAndValue entry : valueSet1 ) for ( NodeAndValue entry : valueSet1 )
{ {
NodeValueIterator nodes = new NodeValueIterator(); NodeValueIterator nodes = new NodeValueIterator();
reader.query( nodes, IndexOrder.NONE, IndexQuery.exact( propertyKeyId, entry.value ) ); reader.query( nodes, IndexOrder.NONE, false, IndexQuery.exact( propertyKeyId, entry.value ) );
assertEquals( entry.value.toString(), asSet( entry.nodeId, entry.nodeId + offset ), PrimitiveLongCollections.toSet( nodes ) ); assertEquals( entry.value.toString(), asSet( entry.nodeId, entry.nodeId + offset ), PrimitiveLongCollections.toSet( nodes ) );
} }
} }
Expand Down
Expand Up @@ -44,4 +44,16 @@ protected boolean spatialRangeSupport()
{ {
return false; return false;
} }

@Override
protected boolean indexProvidesStringValues()
{
return true;
}

@Override
protected boolean indexProvidesNumericValues()
{
return true;
}
} }
Expand Up @@ -65,7 +65,8 @@ public static NodeValueIndexCursor indexSeek( Read read, CursorFactory cursors,
{ {
NodeValueIndexCursor cursor = cursors.allocateNodeValueIndexCursor(); NodeValueIndexCursor cursor = cursors.allocateNodeValueIndexCursor();
IndexQuery.ExactPredicate query = exact( index.properties()[0], makeValueNeoSafe( value ) ); IndexQuery.ExactPredicate query = exact( index.properties()[0], makeValueNeoSafe( value ) );
read.nodeIndexSeek( index, cursor, IndexOrder.NONE, query ); //TODO figure out how to deal with indexes that provide values
read.nodeIndexSeek( index, cursor, IndexOrder.NONE, false, query );
return cursor; return cursor;
} }
} }
Expand Down
Expand Up @@ -22,11 +22,7 @@ package org.neo4j.cypher.internal.spi.v2_3
import java.net.URL import java.net.URL
import java.util.function.Predicate import java.util.function.Predicate


import org.eclipse.collections.api.collection.primitive.ImmutableLongCollection
import org.eclipse.collections.api.iterator.LongIterator import org.eclipse.collections.api.iterator.LongIterator
import org.eclipse.collections.impl.factory.primitive.LongSets
import org.eclipse.collections.impl.iterator.ImmutableEmptyLongIterator
import org.eclipse.collections.impl.utility.internal.primitive.LongIteratorIterate
import org.neo4j.cypher.InternalException import org.neo4j.cypher.InternalException
import org.neo4j.cypher.internal.compiler.v2_3.MinMaxOrdering.{BY_NUMBER, BY_STRING, BY_VALUE} import org.neo4j.cypher.internal.compiler.v2_3.MinMaxOrdering.{BY_NUMBER, BY_STRING, BY_VALUE}
import org.neo4j.cypher.internal.compiler.v2_3._ import org.neo4j.cypher.internal.compiler.v2_3._
Expand All @@ -39,7 +35,7 @@ import org.neo4j.cypher.internal.frontend.v2_3.SemanticDirection.{BOTH, INCOMING
import org.neo4j.cypher.internal.frontend.v2_3.{Bound, EntityNotFoundException, FailedIndexException, SemanticDirection} import org.neo4j.cypher.internal.frontend.v2_3.{Bound, EntityNotFoundException, FailedIndexException, SemanticDirection}
import org.neo4j.cypher.internal.javacompat.GraphDatabaseCypherService import org.neo4j.cypher.internal.javacompat.GraphDatabaseCypherService
import org.neo4j.cypher.internal.runtime.interpreted._ import org.neo4j.cypher.internal.runtime.interpreted._
import org.neo4j.cypher.internal.spi.{CursorIterator, PrimitiveCursorIterator} import org.neo4j.cypher.internal.spi.CursorIterator
import org.neo4j.graphalgo.impl.path.ShortestPath import org.neo4j.graphalgo.impl.path.ShortestPath
import org.neo4j.graphalgo.impl.path.ShortestPath.ShortestPathPredicate import org.neo4j.graphalgo.impl.path.ShortestPath.ShortestPathPredicate
import org.neo4j.graphdb.RelationshipType._ import org.neo4j.graphdb.RelationshipType._
Expand Down Expand Up @@ -231,7 +227,8 @@ final class TransactionBoundQueryContext(tc: TransactionalContextWrapper, val re


private def seek(index: IndexReference, query: IndexQuery*) = { private def seek(index: IndexReference, query: IndexQuery*) = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, query:_*) //older planners cannot use values provided by the index
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, false, query:_*)
new CursorIterator[Node] { new CursorIterator[Node] {
override protected def fetchNext(): Node = { override protected def fetchNext(): Node = {
if (nodeCursor.next()) proxySpi.newNodeProxy(nodeCursor.nodeReference()) if (nodeCursor.next()) proxySpi.newNodeProxy(nodeCursor.nodeReference())
Expand All @@ -242,17 +239,6 @@ final class TransactionBoundQueryContext(tc: TransactionalContextWrapper, val re
} }
} }


private def scan(index: IndexReference) = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE)
new PrimitiveCursorIterator {
override protected def fetchNext(): Long =
if (nodeCursor.next()) nodeCursor.nodeReference() else -1L

override protected def close(): Unit = nodeCursor.close()
}
}

private def indexSeekByPrefixRange(index: SchemaTypes.IndexDescriptor, range: InequalitySeekRange[Any]): scala.Iterator[Node] = { private def indexSeekByPrefixRange(index: SchemaTypes.IndexDescriptor, range: InequalitySeekRange[Any]): scala.Iterator[Node] = {
val groupedRanges = range.groupBy { (bound: Bound[Any]) => val groupedRanges = range.groupBy { (bound: Bound[Any]) =>
bound.endPoint match { bound.endPoint match {
Expand Down Expand Up @@ -357,9 +343,10 @@ final class TransactionBoundQueryContext(tc: TransactionalContextWrapper, val re
}.getOrElse(Iterator.empty) }.getOrElse(Iterator.empty)
} }


def indexScan(index: SchemaTypes.IndexDescriptor) = { def indexScan(index: SchemaTypes.IndexDescriptor): CursorIterator[Node] = {
val cursor = allocateAndTraceNodeValueIndexCursor() val cursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(tc.schemaRead.indexReferenceUnchecked(index.labelId, index.propertyId), cursor, IndexOrder.NONE) //older planners cannot use values provided by the index
reads().nodeIndexScan(tc.schemaRead.indexReferenceUnchecked(index.labelId, index.propertyId), cursor, IndexOrder.NONE, false)
new CursorIterator[Node] { new CursorIterator[Node] {
override protected def fetchNext(): Node = { override protected def fetchNext(): Node = {
if (cursor.next()) proxySpi.newNodeProxy(cursor.nodeReference()) if (cursor.next()) proxySpi.newNodeProxy(cursor.nodeReference())
Expand Down
Expand Up @@ -37,8 +37,8 @@ import org.neo4j.cypher.internal.frontend.v3_1.SemanticDirection.{BOTH, INCOMING
import org.neo4j.cypher.internal.frontend.v3_1.{Bound, EntityNotFoundException, FailedIndexException, SemanticDirection} import org.neo4j.cypher.internal.frontend.v3_1.{Bound, EntityNotFoundException, FailedIndexException, SemanticDirection}
import org.neo4j.cypher.internal.javacompat.GraphDatabaseCypherService import org.neo4j.cypher.internal.javacompat.GraphDatabaseCypherService
import org.neo4j.cypher.internal.runtime.interpreted.ResourceManager import org.neo4j.cypher.internal.runtime.interpreted.ResourceManager
import org.neo4j.cypher.internal.spi.CursorIterator
import org.neo4j.cypher.internal.spi.v3_1.TransactionBoundQueryContext.IndexSearchMonitor import org.neo4j.cypher.internal.spi.v3_1.TransactionBoundQueryContext.IndexSearchMonitor
import org.neo4j.cypher.internal.spi.{CursorIterator, PrimitiveCursorIterator}
import org.neo4j.graphalgo.impl.path.ShortestPath import org.neo4j.graphalgo.impl.path.ShortestPath
import org.neo4j.graphalgo.impl.path.ShortestPath.ShortestPathPredicate import org.neo4j.graphalgo.impl.path.ShortestPath.ShortestPathPredicate
import org.neo4j.graphdb.RelationshipType._ import org.neo4j.graphdb.RelationshipType._
Expand Down Expand Up @@ -224,7 +224,8 @@ final class TransactionBoundQueryContext(txContext: TransactionalContextWrapper,


private def seek(index: IndexReference, query: IndexQuery*) = { private def seek(index: IndexReference, query: IndexQuery*) = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, query:_*) //older planners cannot use values provided by the index
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, false, query:_*)
new CursorIterator[Node] { new CursorIterator[Node] {
override protected def fetchNext(): Node = { override protected def fetchNext(): Node = {
if (nodeCursor.next()) entityAccessor.newNodeProxy(nodeCursor.nodeReference()) if (nodeCursor.next()) entityAccessor.newNodeProxy(nodeCursor.nodeReference())
Expand All @@ -235,17 +236,6 @@ final class TransactionBoundQueryContext(txContext: TransactionalContextWrapper,
} }
} }


private def scan(index: IndexReference) = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE)
new PrimitiveCursorIterator {
override protected def fetchNext(): Long =
if (nodeCursor.next()) nodeCursor.nodeReference() else -1L

override protected def close(): Unit = nodeCursor.close()
}
}

private def indexSeekByPrefixRange(index: IndexDescriptor, range: InequalitySeekRange[Any]): scala.Iterator[Node] = { private def indexSeekByPrefixRange(index: IndexDescriptor, range: InequalitySeekRange[Any]): scala.Iterator[Node] = {
val groupedRanges = range.groupBy { (bound: Bound[Any]) => val groupedRanges = range.groupBy { (bound: Bound[Any]) =>
bound.endPoint match { bound.endPoint match {
Expand Down Expand Up @@ -352,7 +342,8 @@ final class TransactionBoundQueryContext(txContext: TransactionalContextWrapper,


override def indexScan(index: IndexDescriptor) = { override def indexScan(index: IndexDescriptor) = {
val cursor = allocateAndTraceNodeValueIndexCursor() val cursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(txContext.kernelTransaction.schemaRead().indexReferenceUnchecked(index.labelId, index.propertyId), cursor, IndexOrder.NONE) //older planners cannot use values provided by the index
reads().nodeIndexScan(txContext.kernelTransaction.schemaRead().indexReferenceUnchecked(index.labelId, index.propertyId), cursor, IndexOrder.NONE, false)
new CursorIterator[Node] { new CursorIterator[Node] {
override protected def fetchNext(): Node = { override protected def fetchNext(): Node = {
if (cursor.next()) entityAccessor.newNodeProxy(cursor.nodeReference()) if (cursor.next()) entityAccessor.newNodeProxy(cursor.nodeReference())
Expand Down
Expand Up @@ -51,7 +51,7 @@ public void shouldCallIndexSeek() throws KernelException
CompiledIndexUtils.indexSeek( read, mock( CursorFactory.class ), index, "hello" ); CompiledIndexUtils.indexSeek( read, mock( CursorFactory.class ), index, "hello" );


// THEN // THEN
verify( read, times( 1 ) ).nodeIndexSeek( any(), any(), any(), any() ); verify( read, times( 1 ) ).nodeIndexSeek( any(), any(), any(), any(), any() );
} }


@Test @Test
Expand All @@ -67,7 +67,7 @@ public void shouldHandleNullInIndexSeek() throws KernelException
index, null ); index, null );


// THEN // THEN
verify( read, never() ).nodeIndexSeek( any(), any(), any() ); verify( read, never() ).nodeIndexSeek( any(), any(), any(), any() );
assertFalse( cursor.next() ); assertFalse( cursor.next() );
} }
} }
Expand Up @@ -37,6 +37,7 @@ import org.neo4j.graphdb._
import org.neo4j.graphdb.security.URLAccessValidationError import org.neo4j.graphdb.security.URLAccessValidationError
import org.neo4j.graphdb.traversal.{Evaluators, TraversalDescription, Uniqueness} import org.neo4j.graphdb.traversal.{Evaluators, TraversalDescription, Uniqueness}
import org.neo4j.internal.kernel.api import org.neo4j.internal.kernel.api
import org.neo4j.internal.kernel.api.IndexQuery.ExactPredicate
import org.neo4j.internal.kernel.api._ import org.neo4j.internal.kernel.api._
import org.neo4j.internal.kernel.api.exceptions.ProcedureException import org.neo4j.internal.kernel.api.exceptions.ProcedureException
import org.neo4j.internal.kernel.api.helpers.RelationshipSelections.{allCursor, incomingCursor, outgoingCursor} import org.neo4j.internal.kernel.api.helpers.RelationshipSelections.{allCursor, incomingCursor, outgoingCursor}
Expand Down Expand Up @@ -274,20 +275,37 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
properties: Int*): IndexReference = properties: Int*): IndexReference =
transactionalContext.kernelTransaction.schemaRead().index(label, properties: _*) transactionalContext.kernelTransaction.schemaRead().index(label, properties: _*)


private def seek(index: IndexReference, propertyIndicesWithValues: Seq[Int], query: IndexQuery*): CursorIterator[(NodeValue, Seq[Value])] = { private def seek(index: IndexReference, propertyIndicesWithValues: Seq[Int], queries: IndexQuery*): CursorIterator[(NodeValue, Seq[Value])] = {
val nodeCursor: NodeValueIndexCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor: NodeValueIndexCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, query: _*) val actualValues =
if (queries.forall(_.isInstanceOf[ExactPredicate])) {
// We don't need property values from the index for an exact seek
Some(propertyIndicesWithValues.map(queries(_).asInstanceOf[ExactPredicate].value()))
} else {
None
}


val needsValuesFromIndexSeek = actualValues.isEmpty && propertyIndicesWithValues.nonEmpty
reads().nodeIndexSeek(index, nodeCursor, IndexOrder.NONE, needsValuesFromIndexSeek, queries: _*)
new CursorIterator[(NodeValue, Seq[Value])] { new CursorIterator[(NodeValue, Seq[Value])] {
override protected def fetchNext(): (NodeValue, Seq[Value]) = { override protected def fetchNext(): (NodeValue, Seq[Value]) = {
if (nodeCursor.next()) { if (nodeCursor.next()) {
val nodeRef = nodeCursor.nodeReference() val nodeRef = nodeCursor.nodeReference()


if (propertyIndicesWithValues.nonEmpty && !nodeCursor.hasValue) {
// We were promised at plan time that we can get values everywhere, so this should never happen
throw new IllegalStateException("NodeCursor did unexpectedly not have values during index seek.")
}
// Get the actual property values for the requested indices // Get the actual property values for the requested indices
val values = propertyIndicesWithValues.map(nodeCursor.propertyValue) val values = actualValues match {
case Some(v) =>
v
case None =>
if (propertyIndicesWithValues.nonEmpty && !nodeCursor.hasValue) {
// We were promised at plan time that we can get values everywhere, so this should never happen
throw new IllegalStateException("NodeCursor did unexpectedly not have values during index seek.")
}
propertyIndicesWithValues.map(nodeCursor.propertyValue)
}


val node = fromNodeProxy(entityAccessor.newNodeProxy(nodeRef)) val node = fromNodeProxy(entityAccessor.newNodeProxy(nodeRef))
(node, values) (node, values)
} }
Expand All @@ -302,7 +320,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona


override def indexScan(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(NodeValue, Seq[Value])] = { override def indexScan(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(NodeValue, Seq[Value])] = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE) reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE, propertyIndicesWithValues.nonEmpty)
new CursorIterator[(NodeValue, Seq[Value])] { new CursorIterator[(NodeValue, Seq[Value])] {
override protected def fetchNext(): (NodeValue, Seq[Value]) = { override protected def fetchNext(): (NodeValue, Seq[Value]) = {
if (nodeCursor.next()) { if (nodeCursor.next()) {
Expand All @@ -328,7 +346,8 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona


override def indexScanPrimitive(index: IndexReference): PrimitiveLongResourceIterator = { override def indexScanPrimitive(index: IndexReference): PrimitiveLongResourceIterator = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE) // for a primitive cursor, we don't need values
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE, false)
new PrimitiveCursorIterator { new PrimitiveCursorIterator {
override protected def fetchNext(): Long = override protected def fetchNext(): Long =
if (nodeCursor.next()) nodeCursor.nodeReference() else -1L if (nodeCursor.next()) nodeCursor.nodeReference() else -1L
Expand All @@ -339,7 +358,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona


override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(Long, Seq[Value])] = { override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(Long, Seq[Value])] = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor() val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE) reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE, propertyIndicesWithValues.nonEmpty)
new CursorIterator[(Long, Seq[Value])] { new CursorIterator[(Long, Seq[Value])] {
override protected def fetchNext(): (Long, Seq[Value]) = override protected def fetchNext(): (Long, Seq[Value]) =
if (nodeCursor.next()) { if (nodeCursor.next()) {
Expand Down
Expand Up @@ -23,8 +23,8 @@
* Enum used for two purposes: * Enum used for two purposes:
* 1. As return value for {@link IndexCapability#orderCapability(org.neo4j.values.storable.ValueCategory...)}. * 1. As return value for {@link IndexCapability#orderCapability(org.neo4j.values.storable.ValueCategory...)}.
* Only {@link #ASCENDING} and {@link #DESCENDING} is valid for this. * Only {@link #ASCENDING} and {@link #DESCENDING} is valid for this.
* 2. As parameter for {@link Read#nodeIndexScan(IndexReference, NodeValueIndexCursor, IndexOrder)} and * 2. As parameter for {@link Read#nodeIndexScan(IndexReference, NodeValueIndexCursor, IndexOrder, boolean)} and
* {@link Read#nodeIndexSeek(IndexReference, NodeValueIndexCursor, IndexOrder, IndexQuery...)}. Where {@link #NONE} is used when * {@link Read#nodeIndexSeek(IndexReference, NodeValueIndexCursor, IndexOrder, boolean, IndexQuery...)}. Where {@link #NONE} is used when
* no ordering is available or required. * no ordering is available or required.
*/ */
public enum IndexOrder public enum IndexOrder
Expand Down

0 comments on commit c5d93db

Please sign in to comment.