Skip to content

Commit

Permalink
tx-state aware loop count
Browse files Browse the repository at this point in the history
  • Loading branch information
pontusmelke committed Feb 25, 2018
1 parent f3ee486 commit 28d554d
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 26 deletions.
Expand Up @@ -64,8 +64,7 @@ default boolean seek( int relationshipLabel )


default int totalCount() default int totalCount()
{ {
// the outgoingCount and incomingCount both contain the loopCount, so we need to remove it once. return outgoingCount() + incomingCount() + loopCount();
return outgoingCount() + incomingCount() - loopCount();
} }


void outgoing( RelationshipTraversalCursor cursor ); void outgoing( RelationshipTraversalCursor cursor );
Expand Down
Expand Up @@ -26,7 +26,6 @@
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;


import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.Relationship;
import org.neo4j.internal.kernel.api.exceptions.EntityNotFoundException; import org.neo4j.internal.kernel.api.exceptions.EntityNotFoundException;
import org.neo4j.internal.kernel.api.exceptions.KernelException; import org.neo4j.internal.kernel.api.exceptions.KernelException;
Expand All @@ -44,6 +43,9 @@
import static org.neo4j.internal.kernel.api.RelationshipTestSupport.computeKey; import static org.neo4j.internal.kernel.api.RelationshipTestSupport.computeKey;
import static org.neo4j.internal.kernel.api.RelationshipTestSupport.count; import static org.neo4j.internal.kernel.api.RelationshipTestSupport.count;
import static org.neo4j.internal.kernel.api.RelationshipTestSupport.sparse; import static org.neo4j.internal.kernel.api.RelationshipTestSupport.sparse;
import static org.neo4j.internal.kernel.api.RelationshipTransactionStateTestBase.RelationshipDirection.IN;
import static org.neo4j.internal.kernel.api.RelationshipTransactionStateTestBase.RelationshipDirection.LOOP;
import static org.neo4j.internal.kernel.api.RelationshipTransactionStateTestBase.RelationshipDirection.OUT;
import static org.neo4j.values.storable.Values.NO_VALUE; import static org.neo4j.values.storable.Values.NO_VALUE;
import static org.neo4j.values.storable.Values.stringValue; import static org.neo4j.values.storable.Values.stringValue;


Expand Down Expand Up @@ -631,27 +633,52 @@ public void shouldSeeRemovedThenAddedPropertyInTransaction() throws Exception
public void shouldCountFromTxState() throws Exception public void shouldCountFromTxState() throws Exception
{ {
//dense outgoing //dense outgoing
assertCount( 100, OUTGOING, group -> assertCount( 100, OUT, group ->
{ {
assertEquals( 101, group.outgoingCount() ); assertEquals( 101, group.outgoingCount() );
assertEquals( 0, group.incomingCount() );
assertEquals( 0, group.loopCount() );
assertEquals( 101, group.totalCount() ); assertEquals( 101, group.totalCount() );
} ); } );
//sparse outgoing //sparse outgoing
assertCount( 1, OUTGOING, group -> assertCount( 1, OUT, group ->
{ {
assertEquals( 2, group.outgoingCount() ); assertEquals( 2, group.outgoingCount() );
assertEquals( 0, group.incomingCount() );
assertEquals( 0, group.loopCount() );
assertEquals( 2, group.totalCount() ); assertEquals( 2, group.totalCount() );
} ); } );
//dense incoming //dense incoming
assertCount( 100, INCOMING, group -> assertCount( 100, IN, group ->
{ {
assertEquals( 0, group.outgoingCount() );
assertEquals( 101, group.incomingCount() ); assertEquals( 101, group.incomingCount() );
assertEquals( 0, group.outgoingCount() );
assertEquals( 101, group.totalCount() ); assertEquals( 101, group.totalCount() );
} ); } );
//sparse incoming //sparse incoming
assertCount( 1, INCOMING, group -> assertCount( 1, IN, group ->
{ {
assertEquals( 0, group.outgoingCount() );
assertEquals( 2, group.incomingCount() ); assertEquals( 2, group.incomingCount() );
assertEquals( 0, group.loopCount() );
assertEquals( 2, group.totalCount() );
} );

//dense loops
assertCount( 100, LOOP, group ->
{
assertEquals( 0, group.incomingCount() );
assertEquals( 0, group.outgoingCount() );
assertEquals( 101, group.loopCount() );
assertEquals( 101, group.totalCount() );
} );
//sparse loops
assertCount( 1, LOOP, group ->
{
assertEquals( 0, group.outgoingCount() );
assertEquals( 0, group.incomingCount() );
assertEquals( 2, group.loopCount() );
assertEquals( 2, group.totalCount() ); assertEquals( 2, group.totalCount() );
} ); } );
} }
Expand Down Expand Up @@ -824,7 +851,14 @@ private void assertCountRelationships(
assertEquals( expectedCount, count ); assertEquals( expectedCount, count );
} }


private void assertCount( int count, Direction direction, Consumer<RelationshipGroupCursor> asserter) throws Exception enum RelationshipDirection
{
OUT,
IN,
LOOP
}

private void assertCount( int count, RelationshipDirection direction, Consumer<RelationshipGroupCursor> asserter) throws Exception
{ {
long start; long start;
int type; int type;
Expand Down Expand Up @@ -857,20 +891,19 @@ private void assertCount( int count, Direction direction, Consumer<RelationshipG
} }
} }


private void createRelationship( Direction direction, long start, int type, Write write ) private void createRelationship( RelationshipDirection direction, long start, int type, Write write )
throws EntityNotFoundException throws EntityNotFoundException
{ {
switch ( direction ) switch ( direction )
{ {
case OUTGOING: case OUT:
write.relationshipCreate( start, type, write.nodeCreate() ); write.relationshipCreate( start, type, write.nodeCreate() );
break; break;
case INCOMING: case IN:
write.relationshipCreate( write.nodeCreate(), type, start ); write.relationshipCreate( write.nodeCreate(), type, start );
break; break;
case BOTH: case LOOP:
write.relationshipCreate( start, type, write.nodeCreate() ); write.relationshipCreate( start, type, start );
write.relationshipCreate( write.nodeCreate(), type, start );
break; break;
default: default:
throw new IllegalStateException( "Checkstyle, you win again!" ); throw new IllegalStateException( "Checkstyle, you win again!" );
Expand Down
Expand Up @@ -154,7 +154,7 @@ public void shouldTraverseRelationshipsOfGivenType()
degree.incoming ); degree.incoming );
assertEquals( "node #" + node.nodeReference() + " loop", group.loopCount(), degree.loop ); assertEquals( "node #" + node.nodeReference() + " loop", group.loopCount(), degree.loop );
assertEquals( "node #" + node.nodeReference() + " all = incoming + outgoing - loop", assertEquals( "node #" + node.nodeReference() + " all = incoming + outgoing - loop",
group.totalCount(), degree.incoming + degree.outgoing - degree.loop ); group.totalCount(), degree.incoming + degree.outgoing + degree.loop );
} }
if ( none ) if ( none )
{ {
Expand Down
Expand Up @@ -97,6 +97,12 @@ public int augmentDegree( Direction direction, int degree, int typeId )
return degree; return degree;
} }


@Override
public int augmentDegree( RelationshipDirection direction, int degree, int typeId )
{
return degree;
}

@Override @Override
public void accept( NodeState.Visitor visitor ) public void accept( NodeState.Visitor visitor )
{ {
Expand Down Expand Up @@ -280,6 +286,20 @@ public int augmentDegree( Direction direction, int degree, int typeId )
return degree; return degree;
} }


@Override
public int augmentDegree( RelationshipDirection direction, int degree, int typeId )
{
if ( hasAddedRelationships() )
{
degree = relationshipsAdded.augmentDegree( direction, degree, typeId );
}
if ( hasRemovedRelationships() )
{
degree = relationshipsRemoved.augmentDegree( direction, degree, typeId );
}
return degree;
}

@Override @Override
public void accept( NodeState.Visitor visitor ) throws ConstraintValidationException public void accept( NodeState.Visitor visitor ) throws ConstraintValidationException
{ {
Expand Down
Expand Up @@ -315,6 +315,7 @@ public int augmentDegree( Direction direction, int degree )
} }
} }



public int augmentDegree( Direction direction, int degree, int typeId ) public int augmentDegree( Direction direction, int degree, int typeId )
{ {
switch ( direction ) switch ( direction )
Expand Down Expand Up @@ -354,6 +355,36 @@ public int augmentDegree( Direction direction, int degree, int typeId )
return degree; return degree;
} }


public int augmentDegree( RelationshipDirection direction, int degree, int typeId )
{
switch ( direction )
{
case INCOMING:
if ( incoming != null && incoming.containsKey( typeId ) )
{
return diffStrategy.augmentDegree( degree, incoming.get( typeId ).size() );
}
break;
case OUTGOING:
if ( outgoing != null && outgoing.containsKey( typeId ) )
{
return diffStrategy.augmentDegree( degree, outgoing.get( typeId ).size() );
}
break;
case LOOP:
if ( loops != null && loops.containsKey( typeId ) )
{
return diffStrategy.augmentDegree( degree, loops.get( typeId ).size() );
}
break;

default:
throw new IllegalArgumentException( "Unknown direction: " + direction );
}

return degree;
}

public PrimitiveIntSet relationshipTypes() public PrimitiveIntSet relationshipTypes()
{ {
PrimitiveIntSet types = Primitive.intSet(); PrimitiveIntSet types = Primitive.intSet();
Expand Down
Expand Up @@ -27,7 +27,6 @@
import org.neo4j.kernel.impl.newapi.DefaultRelationshipTraversalCursor.Record; import org.neo4j.kernel.impl.newapi.DefaultRelationshipTraversalCursor.Record;
import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord; import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.kernel.impl.store.record.RelationshipRecord; import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.storageengine.api.Direction;


import static org.neo4j.kernel.impl.newapi.RelationshipReferenceEncoding.encodeForFiltering; import static org.neo4j.kernel.impl.newapi.RelationshipReferenceEncoding.encodeForFiltering;
import static org.neo4j.kernel.impl.newapi.RelationshipReferenceEncoding.encodeForTxStateFiltering; import static org.neo4j.kernel.impl.newapi.RelationshipReferenceEncoding.encodeForTxStateFiltering;
Expand Down Expand Up @@ -199,18 +198,15 @@ else if ( isBuffered() )
} }
return read.hasTxStateWithChanges() return read.hasTxStateWithChanges()
? read.txState().getNodeState( getOwningNode() ) ? read.txState().getNodeState( getOwningNode() )
.augmentDegree( Direction.OUTGOING, count, getType() ) : count; .augmentDegree( RelationshipDirection.OUTGOING, count, getType() ) : count;
} }


@Override @Override
public int incomingCount() public int incomingCount()
{ {
int count; int count;
if ( read.hasTxStateWithChanges() && read.txState().nodeIsAddedInThisTx( getOwningNode() ) )
{ if ( isBuffered() )
count = 0;
}
else if ( isBuffered() )
{ {
count = bufferedGroup.incomingCount; count = bufferedGroup.incomingCount;
} }
Expand All @@ -220,17 +216,30 @@ else if ( isBuffered() )
} }
return read.hasTxStateWithChanges() return read.hasTxStateWithChanges()
? read.txState().getNodeState( getOwningNode() ) ? read.txState().getNodeState( getOwningNode() )
.augmentDegree( Direction.INCOMING, count, getType() ) : count; .augmentDegree( RelationshipDirection.INCOMING, count, getType() ) : count;
} }


@Override @Override
public int loopCount() public int loopCount()
{ {
if ( isBuffered() ) int count;
if ( read.hasTxStateWithChanges() && read.txState().nodeIsAddedInThisTx( getOwningNode() ) )
{ {
return bufferedGroup.loopsCount; count = 0;
} }
return count( loopsRawId() ); else if ( isBuffered() )
{
count = bufferedGroup.loopsCount;
}
else
{
count = count( loopsRawId() );
}

return read.hasTxStateWithChanges()
? read.txState().getNodeState( getOwningNode() )
.augmentDegree( RelationshipDirection.LOOP, count, getType() ) : count;

} }


private int count( long reference ) private int count( long reference )
Expand Down
Expand Up @@ -50,6 +50,12 @@ void visitLabelChanges( long nodeId, Set<Integer> added, Set<Integer> removed )


int augmentDegree( Direction direction, int degree, int typeId ); int augmentDegree( Direction direction, int degree, int typeId );


/**
* This method counts all directions separately, i.e.
* total count = count(INCOMING) + count(OUTGOING) + count(LOOPS)
*/
int augmentDegree( RelationshipDirection direction, int degree, int typeId );

void accept( NodeState.Visitor visitor ) throws ConstraintValidationException; void accept( NodeState.Visitor visitor ) throws ConstraintValidationException;


PrimitiveIntSet relationshipTypes(); PrimitiveIntSet relationshipTypes();
Expand Down

0 comments on commit 28d554d

Please sign in to comment.