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()
{
// 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 );
Expand Down
Expand Up @@ -26,7 +26,6 @@
import java.util.Map;
import java.util.function.Consumer;

import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Relationship;
import org.neo4j.internal.kernel.api.exceptions.EntityNotFoundException;
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.count;
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.stringValue;

Expand Down Expand Up @@ -631,27 +633,52 @@ public void shouldSeeRemovedThenAddedPropertyInTransaction() throws Exception
public void shouldCountFromTxState() throws Exception
{
//dense outgoing
assertCount( 100, OUTGOING, group ->
assertCount( 100, OUT, group ->
{
assertEquals( 101, group.outgoingCount() );
assertEquals( 0, group.incomingCount() );
assertEquals( 0, group.loopCount() );
assertEquals( 101, group.totalCount() );
} );
//sparse outgoing
assertCount( 1, OUTGOING, group ->
assertCount( 1, OUT, group ->
{
assertEquals( 2, group.outgoingCount() );
assertEquals( 0, group.incomingCount() );
assertEquals( 0, group.loopCount() );
assertEquals( 2, group.totalCount() );
} );
//dense incoming
assertCount( 100, INCOMING, group ->
assertCount( 100, IN, group ->
{
assertEquals( 0, group.outgoingCount() );
assertEquals( 101, group.incomingCount() );
assertEquals( 0, group.outgoingCount() );
assertEquals( 101, group.totalCount() );
} );
//sparse incoming
assertCount( 1, INCOMING, group ->
assertCount( 1, IN, group ->
{
assertEquals( 0, group.outgoingCount() );
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() );
} );
}
Expand Down Expand Up @@ -824,7 +851,14 @@ private void assertCountRelationships(
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;
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
{
switch ( direction )
{
case OUTGOING:
case OUT:
write.relationshipCreate( start, type, write.nodeCreate() );
break;
case INCOMING:
case IN:
write.relationshipCreate( write.nodeCreate(), type, start );
break;
case BOTH:
write.relationshipCreate( start, type, write.nodeCreate() );
write.relationshipCreate( write.nodeCreate(), type, start );
case LOOP:
write.relationshipCreate( start, type, start );
break;
default:
throw new IllegalStateException( "Checkstyle, you win again!" );
Expand Down
Expand Up @@ -154,7 +154,7 @@ public void shouldTraverseRelationshipsOfGivenType()
degree.incoming );
assertEquals( "node #" + node.nodeReference() + " loop", group.loopCount(), degree.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 )
{
Expand Down
Expand Up @@ -97,6 +97,12 @@ public int augmentDegree( Direction direction, int degree, int typeId )
return degree;
}

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

@Override
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;
}

@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
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 )
{
switch ( direction )
Expand Down Expand Up @@ -354,6 +355,36 @@ public int augmentDegree( Direction direction, int degree, int typeId )
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()
{
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.store.record.RelationshipGroupRecord;
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.encodeForTxStateFiltering;
Expand Down Expand Up @@ -199,18 +198,15 @@ else if ( isBuffered() )
}
return read.hasTxStateWithChanges()
? read.txState().getNodeState( getOwningNode() )
.augmentDegree( Direction.OUTGOING, count, getType() ) : count;
.augmentDegree( RelationshipDirection.OUTGOING, count, getType() ) : count;
}

@Override
public int incomingCount()
{
int count;
if ( read.hasTxStateWithChanges() && read.txState().nodeIsAddedInThisTx( getOwningNode() ) )
{
count = 0;
}
else if ( isBuffered() )

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

@Override
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 )
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 );

/**
* 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;

PrimitiveIntSet relationshipTypes();
Expand Down

0 comments on commit 28d554d

Please sign in to comment.