Skip to content

Commit

Permalink
Use case classes for IndexedNodeWithProperties
Browse files Browse the repository at this point in the history
The case classes IndexedNodeWithProperties and
IndexedPrimitiveNodeWithProperties replace previously used tuples.
This makes it easier to change the definition in one place later one.

Also the signatures of runtime stuff has been changed to use Arrays
instead of Seqs where possible, since we know lengths ahead of time.

This commit also fixes a problem in lockingUniqueIndexSeek where
it tried to get the values from the index, which is not allowed
for ExactPredicates.
  • Loading branch information
sherfert committed Aug 14, 2018
1 parent 27d6d8c commit f58d67e
Show file tree
Hide file tree
Showing 32 changed files with 276 additions and 222 deletions.
Expand Up @@ -312,7 +312,7 @@ class ActualCostCalculationTest extends CypherFunSuite {
val labelToken = LabelToken(LABEL.name(), LabelId(labelId))
val propertyKeyToken = Seq(PropertyKeyToken(PROPERTY, PropertyKeyId(propKeyId)))
// We are calculating the cost including deserialization of values from the index
val properties = propertyKeyToken.map(IndexedProperty(_, getValueFromIndex = true))
val properties = propertyKeyToken.map(IndexedProperty(_, getValueFromIndex = true)).toArray

NodeIndexSeekPipe(LABEL.name(), labelToken, properties, SingleQueryExpression(literal), IndexSeek)()
}
Expand Down
Expand Up @@ -22,9 +22,6 @@
import org.junit.Before;
import org.junit.Test;

import java.util.Collections;
import java.util.Iterator;

import org.neo4j.helpers.collection.Pair;
import org.neo4j.internal.kernel.api.IndexReference;
import org.neo4j.internal.kernel.api.Read;
Expand All @@ -41,7 +38,6 @@
import org.neo4j.values.storable.Values;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.neo4j.internal.kernel.api.IndexQuery.exact;

Expand Down Expand Up @@ -107,15 +103,15 @@ public void shouldFindMatchingNodeWithPropertyValue() throws Exception
// when looking for it
Read read = newTransaction().dataRead();
int propertyId = index.properties()[0];
Pair<Long, Iterable<Value>> result = read.lockingNodeUniqueIndexSeek( index, Collections.singletonList( 0 ), exact( propertyId, value ) );
Pair<Long,Value[]> result = read.lockingNodeUniqueIndexSeek( index, new int[]{0}, exact( propertyId, value ) );
long foundId = result.first();
Iterator<Value> propertyValues = result.other().iterator();
Value[] propertyValues = result.other();
commit();

// then
assertEquals( "Created node was not found", nodeId, foundId );
assertEquals( "Created node had wrong property value", value, propertyValues.next() );
assertFalse( "Created node had too many property values", propertyValues.hasNext());
assertEquals( "Created node had wrong property value", value, propertyValues[0] );
assertEquals( "Created node had too many property values", 1, propertyValues.length);
}

@Test
Expand Down
Expand Up @@ -103,7 +103,7 @@ class ExceptionTranslatingQueryContext(val inner: QueryContext) extends QueryCon
override def dropIndexRule(descriptor: IndexDescriptor) =
translateException(inner.dropIndexRule(descriptor))

override def indexSeek(index: IndexReference, propertyIndicesWithValues: Seq[Int], values: Seq[IndexQuery]): Iterator[(NodeValue, Seq[Value])] =
override def indexSeek(index: IndexReference, propertyIndicesWithValues: Array[Int], values: Seq[IndexQuery]): Iterator[IndexedNodeWithProperties] =
translateException(inner.indexSeek(index, propertyIndicesWithValues, values))

override def getNodesByLabel(id: Int): Iterator[NodeValue] =
Expand Down Expand Up @@ -217,7 +217,7 @@ class ExceptionTranslatingQueryContext(val inner: QueryContext) extends QueryCon
override def getRelTypeName(id: Int) =
translateException(inner.getRelTypeName(id))

override def lockingUniqueIndexSeek(index: IndexReference, propertyIndicesWithValues: Seq[Int], values: Seq[IndexQuery.ExactPredicate]): Option[(NodeValue, Seq[Value])] =
override def lockingUniqueIndexSeek(index: IndexReference, propertyIndicesWithValues: Array[Int], values: Seq[IndexQuery.ExactPredicate]): Option[IndexedNodeWithProperties] =
translateException(inner.lockingUniqueIndexSeek(index, propertyIndicesWithValues, values))

override def getImportURL(url: URL) =
Expand Down Expand Up @@ -247,19 +247,19 @@ class ExceptionTranslatingQueryContext(val inner: QueryContext) extends QueryCon
override def getRelationshipFor(relationshipId: Long, typeId: Int, startNodeId: Long, endNodeId: Long): RelationshipValue =
translateException(inner.getRelationshipFor(relationshipId, typeId, startNodeId, endNodeId))

override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): Iterator[IndexedNodeWithProperties] =
translateException(inner.indexSeekByContains(index, propertyIndicesWithValues, value))

override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): Iterator[IndexedNodeWithProperties] =
translateException(inner.indexSeekByEndsWith(index, propertyIndicesWithValues, value))

override def indexScan(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(NodeValue, Seq[Value])] =
override def indexScan(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedNodeWithProperties] =
translateException(inner.indexScan(index, propertyIndicesWithValues))

override def indexScanPrimitive(index: IndexReference): LongIterator =
translateException(inner.indexScanPrimitive(index))

override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(Long, Seq[Value])] =
override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedPrimitiveNodeWithProperties] =
translateException(inner.indexScanPrimitiveWithValues(index, propertyIndicesWithValues))

override def nodeIsDense(node: Long) =
Expand Down
Expand Up @@ -119,21 +119,21 @@ abstract class DelegatingQueryContext(val inner: QueryContext) extends QueryCont

override def indexReference(label: Int, properties: Int*): IndexReference = singleDbHit(inner.indexReference(label, properties:_*))

override def indexSeek(index: IndexReference, propertyIndicesWithValues: Seq[Int], values: Seq[IndexQuery]): Iterator[(NodeValue, Seq[Value])] =
override def indexSeek(index: IndexReference, propertyIndicesWithValues: Array[Int], values: Seq[IndexQuery]): Iterator[IndexedNodeWithProperties] =
manyDbHits(inner.indexSeek(index, propertyIndicesWithValues, values))

override def indexScan(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(NodeValue, Seq[Value])] =
override def indexScan(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedNodeWithProperties] =
manyDbHits(inner.indexScan(index, propertyIndicesWithValues))

override def indexScanPrimitive(index: IndexReference): LongIterator = manyDbHits(inner.indexScanPrimitive(index))

override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(Long, Seq[Value])] =
override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedPrimitiveNodeWithProperties] =
manyDbHits(inner.indexScanPrimitiveWithValues(index, propertyIndicesWithValues))

override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): scala.Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): scala.Iterator[IndexedNodeWithProperties] =
manyDbHits(inner.indexSeekByContains(index, propertyIndicesWithValues, value))

override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): scala.Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): scala.Iterator[IndexedNodeWithProperties] =
manyDbHits(inner.indexSeekByEndsWith(index, propertyIndicesWithValues, value))

override def getNodesByLabel(id: Int): Iterator[NodeValue] = manyDbHits(inner.getNodesByLabel(id))
Expand Down Expand Up @@ -182,7 +182,8 @@ abstract class DelegatingQueryContext(val inner: QueryContext) extends QueryCont

override def withAnyOpenQueryContext[T](work: (QueryContext) => T): T = inner.withAnyOpenQueryContext(work)

override def lockingUniqueIndexSeek(index: IndexReference, propertyIndicesWithValues: Seq[Int], values: Seq[IndexQuery.ExactPredicate]): Option[(NodeValue, Seq[Value])] =
override def lockingUniqueIndexSeek(index: IndexReference, propertyIndicesWithValues: Array[Int], values: Seq[IndexQuery.ExactPredicate]):
Option[IndexedNodeWithProperties] =
singleDbHit(inner.lockingUniqueIndexSeek(index, propertyIndicesWithValues, values))

override def getRelTypeId(relType: String): Int = singleDbHit(inner.getRelTypeId(relType))
Expand Down
Expand Up @@ -84,11 +84,11 @@ case class InterpretedPipeBuilder(recurse: LogicalPlan => Pipe,
case NodeIndexSeek(ident, label, propertyKeys, valueExpr, _) =>
val indexSeekMode = IndexSeekModeFactory(unique = false, readOnly = readOnly).fromQueryExpression(valueExpr)
// TODO getValueFromIndex
NodeIndexSeekPipe(ident, label, propertyKeys.map(IndexedProperty(_, getValueFromIndex = false)), valueExpr.map(buildExpression), indexSeekMode)(id = id)
NodeIndexSeekPipe(ident, label, propertyKeys.map(IndexedProperty(_, getValueFromIndex = false)).toArray, valueExpr.map(buildExpression), indexSeekMode)(id = id)

case NodeUniqueIndexSeek(ident, label, propertyKeys, valueExpr, _) =>
val indexSeekMode = IndexSeekModeFactory(unique = true, readOnly = readOnly).fromQueryExpression(valueExpr)
NodeIndexSeekPipe(ident, label, propertyKeys.map(IndexedProperty(_, getValueFromIndex = false)), valueExpr.map(buildExpression), indexSeekMode)(id = id)
NodeIndexSeekPipe(ident, label, propertyKeys.map(IndexedProperty(_, getValueFromIndex = false)).toArray, valueExpr.map(buildExpression), indexSeekMode)(id = id)

case NodeIndexScan(ident, label, propertyKey, _) =>
NodeIndexScanPipe(ident, label, propertyKey, getValueFromIndex = false)(id = id)
Expand Down
Expand Up @@ -258,7 +258,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
ValueGroup.ZONED_TIME,
ValueGroup.DURATION)

override def indexSeek(index: IndexReference, propertyIndicesWithValues: Seq[Int], predicates: Seq[IndexQuery]): Iterator[(NodeValue, Seq[Value])] = {
override def indexSeek(index: IndexReference, propertyIndicesWithValues: Array[Int], predicates: Seq[IndexQuery]): Iterator[IndexedNodeWithProperties] = {

val impossiblePredicate =
predicates.exists {
Expand All @@ -275,7 +275,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
properties: Int*): IndexReference =
transactionalContext.kernelTransaction.schemaRead().index(label, properties: _*)

private def seek(index: IndexReference, propertyIndicesWithValues: Seq[Int], queries: IndexQuery*): CursorIterator[(NodeValue, Seq[Value])] = {
private def seek(index: IndexReference, propertyIndicesWithValues: Array[Int], queries: IndexQuery*): CursorIterator[IndexedNodeWithProperties] = {
val nodeCursor: NodeValueIndexCursor = allocateAndTraceNodeValueIndexCursor()
val actualValues =
if (queries.forall(_.isInstanceOf[ExactPredicate])) {
Expand All @@ -288,8 +288,8 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona

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

Expand All @@ -307,7 +307,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona


val node = fromNodeProxy(entityAccessor.newNodeProxy(nodeRef))
(node, values)
IndexedNodeWithProperties(node, values)
}
else {
null
Expand All @@ -318,11 +318,11 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
}
}

override def indexScan(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(NodeValue, Seq[Value])] = {
override def indexScan(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedNodeWithProperties] = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE, propertyIndicesWithValues.nonEmpty)
new CursorIterator[(NodeValue, Seq[Value])] {
override protected def fetchNext(): (NodeValue, Seq[Value]) = {
new CursorIterator[IndexedNodeWithProperties] {
override protected def fetchNext(): IndexedNodeWithProperties = {
if (nodeCursor.next()) {
val nodeRef = nodeCursor.nodeReference()

Expand All @@ -333,7 +333,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
// Get the actual property values for the requested indices
val values = propertyIndicesWithValues.map(nodeCursor.propertyValue)
val node = fromNodeProxy(entityAccessor.newNodeProxy(nodeRef))
(node, values)
IndexedNodeWithProperties(node, values)
}
else {
null
Expand All @@ -356,11 +356,11 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
}
}

override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Seq[Int]): Iterator[(Long, Seq[Value])] = {
override def indexScanPrimitiveWithValues(index: IndexReference, propertyIndicesWithValues: Array[Int]): Iterator[IndexedPrimitiveNodeWithProperties] = {
val nodeCursor = allocateAndTraceNodeValueIndexCursor()
reads().nodeIndexScan(index, nodeCursor, IndexOrder.NONE, propertyIndicesWithValues.nonEmpty)
new CursorIterator[(Long, Seq[Value])] {
override protected def fetchNext(): (Long, Seq[Value]) =
new CursorIterator[IndexedPrimitiveNodeWithProperties] {
override protected def fetchNext(): IndexedPrimitiveNodeWithProperties =
if (nodeCursor.next()) {
val nodeRef = nodeCursor.nodeReference()

Expand All @@ -370,7 +370,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
}
// Get the actual property values for the requested indices
val values = propertyIndicesWithValues.map(nodeCursor.propertyValue)
(nodeRef, values)
IndexedPrimitiveNodeWithProperties(nodeRef, values)
} else {
null
}
Expand All @@ -379,26 +379,25 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona
}
}

override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByContains(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): Iterator[IndexedNodeWithProperties] =
seek(index, propertyIndicesWithValues, IndexQuery.stringContains(index.properties()(0), value))

override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Seq[Int], value: String): Iterator[(NodeValue, Seq[Value])] =
override def indexSeekByEndsWith(index: IndexReference, propertyIndicesWithValues: Array[Int], value: String): Iterator[IndexedNodeWithProperties] =
seek(index, propertyIndicesWithValues, IndexQuery.stringSuffix(index.properties()(0), value))

override def lockingUniqueIndexSeek(indexReference: IndexReference, propertyIndicesWithValues: Seq[Int], queries: Seq[IndexQuery.ExactPredicate]): Option[(NodeValue, Seq[Value])] = {
override def lockingUniqueIndexSeek(indexReference: IndexReference, propertyIndicesWithValues: Array[Int], queries: Seq[IndexQuery.ExactPredicate]): Option[IndexedNodeWithProperties] = {
indexSearchMonitor.lockingUniqueIndexSeek(indexReference, queries)
if (queries.exists(q => q.value() == Values.NO_VALUE))
None
else {
val index = transactionalContext.kernelTransaction.schemaRead().indexReferenceUnchecked(indexReference.schema())
val pair = reads().lockingNodeUniqueIndexSeek(index, propertyIndicesWithValues.map(i => i:Integer).asJava, queries: _*)
val pair = reads().lockingNodeUniqueIndexSeek(index, propertyIndicesWithValues, queries: _*)
val (nodeId, values) = (pair.first(), pair.other())
if (StatementConstants.NO_SUCH_NODE == nodeId) {
None
} else {
val nodeValue = nodeOps.getById(nodeId)
val valuesAsSeq = values.asScala.toSeq
Some((nodeValue, valuesAsSeq))
Some(IndexedNodeWithProperties(nodeValue, values))
}
}
}
Expand Down
Expand Up @@ -19,9 +19,8 @@
*/
package org.neo4j.cypher.internal.runtime.interpreted.pipes

import org.neo4j.cypher.internal.runtime.IndexedNodeWithProperties
import org.neo4j.cypher.internal.runtime.interpreted.ExecutionContext
import org.neo4j.values.storable.Value
import org.neo4j.values.virtual.NodeValue

/**
* Provides a helper method for index pipes that get nodes together with actual property values.
Expand All @@ -31,17 +30,17 @@ trait IndexPipeWithValues extends Pipe {
// Name of the node variable
val ident: String
// all indices where the index can provide values
val propertyIndicesWithValues: Seq[Int]
val propertyIndicesWithValues: Array[Int]
// the names of the properties where we will get values
val propertyNamesWithValues: Seq[String]
val propertyNamesWithValues: Array[String]

/**
* Create an Iterator of ExecutionContexts given an Iterator of tuples of nodes and property values,
* by copying the node and all values into the given baseContext.
*/
def createResultsFromTupleIterator(baseContext: ExecutionContext, tupleIterator: Iterator[(NodeValue, Seq[Value])]): Iterator[ExecutionContext] = {
def createResultsFromTupleIterator(baseContext: ExecutionContext, tupleIterator: Iterator[IndexedNodeWithProperties]): Iterator[ExecutionContext] = {
tupleIterator.map {
case (node, values) =>
case IndexedNodeWithProperties(node, values) =>
val valueEntries = propertyIndicesWithValues.map(offset => propertyNamesWithValues(offset) -> values(offset) )
val newEntries = (ident -> node) +: valueEntries
executionContextFactory.copyWith(baseContext, newEntries)
Expand Down
Expand Up @@ -31,8 +31,8 @@ case class NodeIndexScanPipe(ident: String,
getValueFromIndex: Boolean)
(val id: Id = Id.INVALID_ID) extends Pipe with IndexPipeWithValues {

override val propertyIndicesWithValues: Seq[Int] = if (getValueFromIndex) Seq(0) else Seq.empty
override val propertyNamesWithValues: Seq[String] = if (getValueFromIndex) Seq(ident + "." + propertyKey.name) else Seq.empty
override val propertyIndicesWithValues: Array[Int] = if (getValueFromIndex) Array(0) else Array.empty
override val propertyNamesWithValues: Array[String] = if (getValueFromIndex) Array(ident + "." + propertyKey.name) else Array.empty


private var reference: IndexReference = IndexReference.NO_INDEX
Expand Down

0 comments on commit f58d67e

Please sign in to comment.