Skip to content

Commit

Permalink
Migrate Core API NodeProxy.getRelationships impl to Kernel API
Browse files Browse the repository at this point in the history
  • Loading branch information
fickludd authored and pontusmelke committed Feb 1, 2018
1 parent ad32c25 commit 9befc43
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 90 deletions.
Expand Up @@ -42,6 +42,7 @@
import org.neo4j.internal.kernel.api.LabelSet; import org.neo4j.internal.kernel.api.LabelSet;
import org.neo4j.internal.kernel.api.NodeCursor; import org.neo4j.internal.kernel.api.NodeCursor;
import org.neo4j.internal.kernel.api.PropertyCursor; import org.neo4j.internal.kernel.api.PropertyCursor;
import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
import org.neo4j.internal.kernel.api.TokenRead; import org.neo4j.internal.kernel.api.TokenRead;
import org.neo4j.internal.kernel.api.exceptions.InvalidTransactionTypeKernelException; import org.neo4j.internal.kernel.api.exceptions.InvalidTransactionTypeKernelException;
import org.neo4j.internal.kernel.api.exceptions.KernelException; import org.neo4j.internal.kernel.api.exceptions.KernelException;
Expand Down Expand Up @@ -125,30 +126,9 @@ public ResourceIterable<Relationship> getRelationships()
} }


@Override @Override
public ResourceIterable<Relationship> getRelationships( final Direction dir ) public ResourceIterable<Relationship> getRelationships( final Direction direction )
{ {
assertInUnterminatedTransaction(); return innerGetRelationships( direction, null );
return () ->
{
Statement statement = spi.statement();
try
{
RelationshipConversion result = new RelationshipConversion( spi );
result.iterator = statement.readOperations().nodeGetRelationships( nodeId, dir );
result.statement = statement;
return result;
}
catch ( EntityNotFoundException e )
{
statement.close();
throw new NotFoundException( format( "Node %d not found", nodeId ), e );
}
catch ( Throwable e )
{
statement.close();
throw e;
}
};
} }


@Override @Override
Expand All @@ -171,25 +151,31 @@ public ResourceIterable<Relationship> getRelationships( final Direction directio
{ {
typeIds = relTypeIds( types, statement ); typeIds = relTypeIds( types, statement );
} }
return innerGetRelationships( direction, typeIds );
}

private ResourceIterable<Relationship> innerGetRelationships( final Direction direction, int[] typeIds )
{
assertInUnterminatedTransaction();
return () -> return () ->
{ {
Statement statement = spi.statement(); KernelTransaction transaction = safeAcquireTransaction();
try NodeCursor node = transaction.nodeCursor();
transaction.dataRead().singleNode( getId(), node );
if ( !node.next() )
{ {
RelationshipConversion result = new RelationshipConversion( spi ); throw new NotFoundException( format( "Node %d not found", nodeId ) );
result.iterator = statement.readOperations().nodeGetRelationships(
nodeId, direction, typeIds );
result.statement = statement;
return result;
} }
catch ( EntityNotFoundException e )
RelationshipTraversalCursor relationship = transaction.cursors().allocateRelationshipTraversalCursor();
try
{ {
statement.close(); node.allRelationships( relationship );
throw new NotFoundException( format( "Node %d not found", nodeId ), e ); return new RelationshipConversion( spi, relationship, direction, typeIds );
} }
catch ( Throwable e ) catch ( Throwable e )
{ {
statement.close(); relationship.close();
throw e; throw e;
} }
}; };
Expand Down
Expand Up @@ -19,42 +19,68 @@
*/ */
package org.neo4j.kernel.impl.core; package org.neo4j.kernel.impl.core;


import org.apache.commons.lang3.ArrayUtils;

import java.util.NoSuchElementException; import java.util.NoSuchElementException;


import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.kernel.api.Statement; import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
import org.neo4j.kernel.impl.api.RelationshipVisitor;
import org.neo4j.kernel.impl.api.store.RelationshipIterator;


public class RelationshipConversion implements RelationshipVisitor<RuntimeException>, ResourceIterator<Relationship> public class RelationshipConversion implements ResourceIterator<Relationship>
{ {
private final EmbeddedProxySPI actions; private final EmbeddedProxySPI actions;
RelationshipIterator iterator; private final RelationshipTraversalCursor cursor;
Statement statement; private final Direction direction;
private final int[] typeIds;
private Relationship next; private Relationship next;
private boolean closed; private boolean closed;


public RelationshipConversion( EmbeddedProxySPI actions ) public RelationshipConversion(
EmbeddedProxySPI actions,
RelationshipTraversalCursor cursor,
Direction direction,
int[] typeIds)
{ {
this.actions = actions; this.actions = actions;
} this.cursor = cursor;

this.direction = direction;
@Override this.typeIds = typeIds;
public void visit( long relId, int type, long startNode, long endNode ) throws RuntimeException
{
next = actions.newRelationshipProxy( relId, startNode, type, endNode );
} }


@Override @Override
public boolean hasNext() public boolean hasNext()
{ {
boolean hasNext = iterator.hasNext(); if ( next == null && !closed )
if ( !hasNext )
{ {
while ( cursor.next() )
{
if ( correctDirection() && correctType() )
{
next = actions.newRelationshipProxy(
cursor.relationshipReference(),
cursor.sourceNodeReference(),
cursor.label(),
cursor.targetNodeReference() );
return true;
}
}
close(); close();
} }
return hasNext; return next != null;
}

private boolean correctDirection()
{
return direction == Direction.BOTH ||
(direction == Direction.OUTGOING && cursor.originNodeReference() == cursor.sourceNodeReference()) ||
(direction == Direction.INCOMING && cursor.originNodeReference() == cursor.targetNodeReference());
}

private boolean correctType()
{
return typeIds == null || ArrayUtils.contains( typeIds, cursor.label() );
} }


@Override @Override
Expand All @@ -64,7 +90,6 @@ public Relationship next()
{ {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
iterator.relationshipVisit( iterator.next(), this );
Relationship current = next; Relationship current = next;
next = null; next = null;
return current; return current;
Expand All @@ -81,7 +106,7 @@ public void close()
{ {
if ( !closed ) if ( !closed )
{ {
statement.close(); cursor.close();
closed = true; closed = true;
} }
} }
Expand Down
Expand Up @@ -22,59 +22,66 @@
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import org.neo4j.kernel.api.Statement; import org.neo4j.graphdb.Direction;
import org.neo4j.kernel.impl.api.RelationshipVisitor; import org.neo4j.internal.kernel.api.RelationshipTraversalCursor;
import org.neo4j.kernel.impl.api.store.RelationshipIterator;


import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


public class RelationshipConversionTest public class RelationshipConversionTest
{ {


private EmbeddedProxySPI nodeActions = mock( EmbeddedProxySPI.class ); private EmbeddedProxySPI nodeActions = mock( EmbeddedProxySPI.class );
private Statement statement = mock( Statement.class );
private RelationshipConversion relationshipConversion; private RelationshipConversion relationshipConversion;
private RelationshipTraversalCursor cursor;


@Before @Before
public void setUp() public void setUp()
{ {
relationshipConversion = new RelationshipConversion( nodeActions ); when( nodeActions.newRelationshipProxy( anyLong(), anyLong(), anyInt(), anyLong() ) )
relationshipConversion.statement = statement; .thenReturn( new RelationshipProxy( null, 1 ) );

cursor = mock( RelationshipTraversalCursor.class );
relationshipConversion = new RelationshipConversion( nodeActions, cursor, Direction.BOTH, null );
} }


@Test @Test
public void closeStatementOnClose() throws Exception public void closeStatementOnClose() throws Exception
{ {
when( cursor.next() ).thenReturn( false );

relationshipConversion.close(); relationshipConversion.close();


verify( statement ).close(); verify( cursor ).close();
} }


@Test @Test
public void closeStatementWhenIterationIsOver() public void closeStatementWhenIterationIsOver()
{ {
relationshipConversion.iterator = new ArrayRelationshipVisitor( new long[]{1L, 8L} ); when( cursor.next() ).thenReturn( true, true, false );


assertTrue( relationshipConversion.hasNext() ); assertTrue( relationshipConversion.hasNext() );
relationshipConversion.next(); relationshipConversion.next();
verify( statement, never() ).close(); verify( cursor, never() ).close();


assertTrue( relationshipConversion.hasNext() ); assertTrue( relationshipConversion.hasNext() );
relationshipConversion.next(); relationshipConversion.next();
verify( statement, never() ).close(); verify( cursor, never() ).close();


assertFalse( relationshipConversion.hasNext() ); assertFalse( relationshipConversion.hasNext() );
verify( statement ).close(); verify( cursor ).close();
} }


@Test @Test
public void closeStatementOnlyOnce() public void closeStatementOnlyOnce()
{ {
relationshipConversion.iterator = new ArrayRelationshipVisitor( new long[]{1L} ); when( cursor.next() ).thenReturn( true, false );


assertTrue( relationshipConversion.hasNext() ); assertTrue( relationshipConversion.hasNext() );
relationshipConversion.next(); relationshipConversion.next();
Expand All @@ -85,31 +92,6 @@ public void closeStatementOnlyOnce()
relationshipConversion.close(); relationshipConversion.close();
relationshipConversion.close(); relationshipConversion.close();


verify( statement ).close(); verify( cursor ).close();
}

private static class ArrayRelationshipVisitor extends RelationshipIterator.BaseIterator
{
private final long[] ids;
private int position;

ArrayRelationshipVisitor( long[] ids )
{
this.ids = ids;
}

@Override
protected boolean fetchNext()
{
return ids.length > position && next( ids[position++] );
}

@Override
public <EXCEPTION extends Exception> boolean relationshipVisit( long relationshipId,
RelationshipVisitor<EXCEPTION> visitor ) throws EXCEPTION
{
visitor.visit( relationshipId, 1, 1L, 1L );
return false;
}
} }
} }

0 comments on commit 9befc43

Please sign in to comment.