Skip to content

Commit

Permalink
Add lockingUniqueIndexSeek with values
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sherfert committed Aug 14, 2018
1 parent 22fd5e0 commit 79832e7
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 4 deletions.
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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<Long, Iterable<Value>> result = read.lockingNodeUniqueIndexSeek( index, Collections.singletonList( 0 ), exact( propertyId, value ) );
long foundId = result.first();
Iterator<Value> 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
{
Expand Down Expand Up @@ -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
Expand Down
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Long, Iterable<Value>> lockingNodeUniqueIndexSeek( IndexReference index, List<Integer> propertyIndicesWithValues,
IndexQuery.ExactPredicate... predicates )
throws KernelException;

/**
* Scan all values in an index.
*
Expand Down
Expand Up @@ -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;
Expand All @@ -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
{
Expand All @@ -49,6 +53,13 @@ public long lockingNodeUniqueIndexSeek( IndexReference index,
throw new UnsupportedOperationException();
}

@Override
public Pair<Long,Iterable<Value>> lockingNodeUniqueIndexSeek( IndexReference index, List<Integer> propertyIndicesWithValues,
IndexQuery.ExactPredicate... predicates ) throws KernelException
{
throw new UnsupportedOperationException();
}

@Override
public void nodeIndexScan( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder )
{
Expand Down
Expand Up @@ -53,6 +53,7 @@ final class DefaultNodeValueIndexCursor extends IndexCursor<IndexProgressor>
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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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() )
{
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -151,6 +155,14 @@ public final long lockingNodeUniqueIndexSeek(
IndexReference index,
IndexQuery.ExactPredicate... predicates )
throws IndexNotApplicableKernelException, IndexNotFoundKernelException, IndexBrokenKernelException
{
Pair<Long,Iterable<Value>> pair = lockingNodeUniqueIndexSeek( index, Collections.emptyList(), predicates );
return pair.first();
}

@Override
public Pair<Long,Iterable<Value>> lockingNodeUniqueIndexSeek( IndexReference index, List<Integer> propertyIndicesWithValues,
IndexQuery.ExactPredicate... predicates ) throws IndexNotApplicableKernelException, IndexNotFoundKernelException, IndexBrokenKernelException
{
assertIndexOnline( index );
assertPredicatesMatchSchema( index, predicates );
Expand Down Expand Up @@ -183,7 +195,13 @@ public final long lockingNodeUniqueIndexSeek(
}
}

return cursor.nodeReference();
List<Value> values = new ArrayList<>( propertyIndicesWithValues.size() );
for ( int offset : propertyIndicesWithValues )
{
values.add( cursor.propertyValue( offset ) );
}

return Pair.of( cursor.nodeReference(), values );
}
}

Expand Down

0 comments on commit 79832e7

Please sign in to comment.