From 79832e74e8c4ab417ece3e3bc0b36d84e0b06b2f Mon Sep 17 00:00:00 2001 From: Satia Herfert Date: Mon, 30 Jul 2018 16:19:38 +0200 Subject: [PATCH] Add lockingUniqueIndexSeek with values All other index operators initialize cursors, from which one can get the property values if available. lockingUniqueIndexSeek is different and only returns a long. Now there is a second method that return a tuple. --- .../NodeGetUniqueFromIndexSeekIT.java | 30 +++++++++++++++++-- .../org/neo4j/internal/kernel/api/Read.java | 22 ++++++++++++++ .../internal/kernel/api/helpers/StubRead.java | 11 +++++++ .../newapi/DefaultNodeValueIndexCursor.java | 4 ++- .../org/neo4j/kernel/impl/newapi/Read.java | 20 ++++++++++++- 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java index 27cf739878a0a..706c1b1a45d71 100644 --- a/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java +++ b/community/community-it/kernel-it/src/test/java/org/neo4j/kernel/impl/api/integrationtest/NodeGetUniqueFromIndexSeekIT.java @@ -22,6 +22,10 @@ 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; import org.neo4j.internal.kernel.api.TokenWrite; @@ -37,6 +41,7 @@ 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; @@ -91,6 +96,28 @@ public void shouldFindMatchingNode() throws Exception assertEquals( "Created node was not found", nodeId, foundId ); } + @Test + public void shouldFindMatchingNodeWithPropertyValue() throws Exception + { + // given + IndexReference index = createUniquenessConstraint( labelId, propertyId1 ); + Value value = Values.of( "value" ); + long nodeId = createNodeWithValue( value ); + + // when looking for it + Read read = newTransaction().dataRead(); + int propertyId = index.properties()[0]; + Pair> result = read.lockingNodeUniqueIndexSeek( index, Collections.singletonList( 0 ), exact( propertyId, value ) ); + long foundId = result.first(); + Iterator propertyValues = result.other().iterator(); + 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()); + } + @Test public void shouldNotFindNonMatchingNode() throws Exception { @@ -120,8 +147,7 @@ public void shouldCompositeFindMatchingNode() throws Exception // when looking for it Transaction transaction = newTransaction(); long foundId = transaction.dataRead().lockingNodeUniqueIndexSeek( index, - exact( propertyId1, value1 ), - exact( propertyId2, value2 ) ); + exact( propertyId1, value1 ), exact( propertyId2, value2 ) ); commit(); // then diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/Read.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/Read.java index d0d5410e93bbb..faf28a3bab385 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/Read.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/Read.java @@ -19,7 +19,11 @@ */ package org.neo4j.internal.kernel.api; +import java.util.List; + +import org.neo4j.helpers.collection.Pair; import org.neo4j.internal.kernel.api.exceptions.KernelException; +import org.neo4j.values.storable.Value; /** * Defines the graph read operations of the Kernel. @@ -55,6 +59,24 @@ void nodeIndexSeek( IndexReference index, NodeValueIndexCursor cursor, IndexOrde long lockingNodeUniqueIndexSeek( IndexReference index, IndexQuery.ExactPredicate... predicates ) throws KernelException; + /** + * Returns node id of node found in unique index or -1 if no node was found. Also returns the properties + * of the node that the index provides, at the indices indicated by `propertyIndicesWithValues`. + * + * Note that this is a very special method and should be use with caution. It has special locking semantics in + * order to facilitate unique creation of nodes. If a node is found; a shared lock for the index entry will be + * held whereas if no node is found we will hold onto an exclusive lock until the close of the transaction. + * + * @param index {@link IndexReference} referencing index to query. + * {@link IndexReference referenced index}, or {@link IndexOrder#NONE}. + * @param propertyIndicesWithValues the indices of properties for which the index should retrieve values. This should be empty + * if the index cannot provide values, index 0 for a non-composite index, and more indices for a composite index. + * @param predicates Combination of {@link IndexQuery.ExactPredicate index queries} to run against referenced index. + */ + Pair> lockingNodeUniqueIndexSeek( IndexReference index, List propertyIndicesWithValues, + IndexQuery.ExactPredicate... predicates ) + throws KernelException; + /** * Scan all values in an index. * diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/helpers/StubRead.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/helpers/StubRead.java index c26a6ef023f1d..ebce8722c814d 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/helpers/StubRead.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/helpers/StubRead.java @@ -19,6 +19,9 @@ */ package org.neo4j.internal.kernel.api.helpers; +import java.util.List; + +import org.neo4j.helpers.collection.Pair; import org.neo4j.internal.kernel.api.IndexOrder; import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.internal.kernel.api.IndexReference; @@ -32,6 +35,7 @@ import org.neo4j.internal.kernel.api.RelationshipTraversalCursor; import org.neo4j.internal.kernel.api.Scan; import org.neo4j.internal.kernel.api.exceptions.KernelException; +import org.neo4j.values.storable.Value; public class StubRead implements Read { @@ -49,6 +53,13 @@ public long lockingNodeUniqueIndexSeek( IndexReference index, throw new UnsupportedOperationException(); } + @Override + public Pair> lockingNodeUniqueIndexSeek( IndexReference index, List propertyIndicesWithValues, + IndexQuery.ExactPredicate... predicates ) throws KernelException + { + throw new UnsupportedOperationException(); + } + @Override public void nodeIndexScan( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/DefaultNodeValueIndexCursor.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/DefaultNodeValueIndexCursor.java index 5bf8d22589944..dceb1aee16f86 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/DefaultNodeValueIndexCursor.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/DefaultNodeValueIndexCursor.java @@ -53,6 +53,7 @@ final class DefaultNodeValueIndexCursor extends IndexCursor private Value[] values; private LongIterator added = ImmutableEmptyLongIterator.INSTANCE; private LongSet removed = LongSets.immutable.empty(); + // TODO This should not be set simply to true. The NodeIndexSeeker should dictate that, either on creation or on initialize private boolean needsValues; private final DefaultCursors pool; @@ -134,6 +135,7 @@ public boolean next() if ( added.hasNext() ) { this.node = added.next(); + // TODO we need to get the values also for added nodes (from the TXState)! this.values = null; return true; } @@ -291,7 +293,7 @@ private void suffixOrContainsQuery( IndexDescriptor descriptor, IndexQuery query private void seekQuery( IndexDescriptor descriptor, IndexQuery[] query ) { - needsValues = false; + needsValues = true; IndexQuery.ExactPredicate[] exactPreds = assertOnlyExactPredicates( query ); if ( read.hasTxStateWithChanges() ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java index 1ce58af186cfb..298902cb407d1 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java @@ -19,8 +19,12 @@ */ package org.neo4j.kernel.impl.newapi; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.neo4j.helpers.collection.Pair; import org.neo4j.internal.kernel.api.IndexOrder; import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.internal.kernel.api.IndexReference; @@ -151,6 +155,14 @@ public final long lockingNodeUniqueIndexSeek( IndexReference index, IndexQuery.ExactPredicate... predicates ) throws IndexNotApplicableKernelException, IndexNotFoundKernelException, IndexBrokenKernelException + { + Pair> pair = lockingNodeUniqueIndexSeek( index, Collections.emptyList(), predicates ); + return pair.first(); + } + + @Override + public Pair> lockingNodeUniqueIndexSeek( IndexReference index, List propertyIndicesWithValues, + IndexQuery.ExactPredicate... predicates ) throws IndexNotApplicableKernelException, IndexNotFoundKernelException, IndexBrokenKernelException { assertIndexOnline( index ); assertPredicatesMatchSchema( index, predicates ); @@ -183,7 +195,13 @@ public final long lockingNodeUniqueIndexSeek( } } - return cursor.nodeReference(); + List values = new ArrayList<>( propertyIndicesWithValues.size() ); + for ( int offset : propertyIndicesWithValues ) + { + values.add( cursor.propertyValue( offset ) ); + } + + return Pair.of( cursor.nodeReference(), values ); } }