Skip to content

Commit

Permalink
TxState aware relationship traversal of non-dense node
Browse files Browse the repository at this point in the history
  • Loading branch information
fickludd committed Jan 23, 2018
1 parent 0cea7cc commit 573c5a3
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 37 deletions.
Expand Up @@ -93,4 +93,98 @@ public void shouldNotSeeSingleRelationshipWhichWasDeletedInTransaction() throws
tx.success();
}
}

@Test
public void shouldSeeRelationshipInTransaction() throws Exception
{
long n1, n2;
try ( Transaction tx = session.beginTransaction() )
{
n1 = tx.dataWrite().nodeCreate();
n2 = tx.dataWrite().nodeCreate();
tx.success();
}

try ( Transaction tx = session.beginTransaction() )
{
int label = tx.tokenWrite().relationshipTypeGetOrCreateForName( "R" );
long r = tx.dataWrite().relationshipCreate( n1, label, n2 );
try ( NodeCursor node = cursors.allocateNodeCursor();
RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() )
{
tx.dataRead().singleNode( n1, node );
assertTrue( "should access node", node.next() );

node.allRelationships( relationship );
assertTrue( "should find relationship", relationship.next() );
assertEquals( r, relationship.relationshipReference() );

assertFalse( "should only find one relationship", relationship.next() );
}
tx.success();
}
}

@Test
public void shouldNotSeeRelationshipDeletedInTransaction() throws Exception
{
long n1, n2, r;
try ( Transaction tx = session.beginTransaction() )
{
n1 = tx.dataWrite().nodeCreate();
n2 = tx.dataWrite().nodeCreate();

int label = tx.tokenWrite().relationshipTypeGetOrCreateForName( "R" );
r = tx.dataWrite().relationshipCreate( n1, label, n2 );

tx.success();
}

try ( Transaction tx = session.beginTransaction() )
{
tx.dataWrite().relationshipDelete( r );
try ( NodeCursor node = cursors.allocateNodeCursor();
RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() )
{
tx.dataRead().singleNode( n1, node );
assertTrue( "should access node", node.next() );

node.allRelationships( relationship );
assertFalse( "should not find relationship", relationship.next() );
}
tx.success();
}
}

@Test
public void shouldSeeRelationshipInTransactionBeforeCursorInitialization() throws Exception
{
long n1, n2;
try ( Transaction tx = session.beginTransaction() )
{
n1 = tx.dataWrite().nodeCreate();
n2 = tx.dataWrite().nodeCreate();
tx.success();
}

try ( Transaction tx = session.beginTransaction() )
{
int label = tx.tokenWrite().relationshipTypeGetOrCreateForName( "R" );
long r = tx.dataWrite().relationshipCreate( n1, label, n2 );
try ( NodeCursor node = cursors.allocateNodeCursor();
RelationshipTraversalCursor relationship = cursors.allocateRelationshipTraversalCursor() )
{
tx.dataRead().singleNode( n1, node );
assertTrue( "should access node", node.next() );

node.allRelationships( relationship );
assertTrue( "should find relationship", relationship.next() );
assertEquals( r, relationship.relationshipReference() );

tx.dataWrite().relationshipCreate( n1, label, n2 ); // should not be seen
assertFalse( "should not find relationship added after cursor init", relationship.next() );
}
tx.success();
}
}
}
Expand Up @@ -697,7 +697,7 @@ public Cursor<RelationshipItem> augmentNodeRelationshipCursor( Cursor<Relationsh
NodeState nodeState,
Direction direction )
{
return nodeState.hasPropertyChanges() || nodeState.hasRelationshipChanges()
return nodeState.hasRelationshipChanges()
? iteratorRelationshipCursor.get().init( cursor, nodeState.getAddedRelationships( direction ) )
: cursor;
}
Expand All @@ -707,7 +707,7 @@ public Cursor<RelationshipItem> augmentNodeRelationshipCursor( Cursor<Relationsh
Direction direction,
int[] relTypes )
{
return nodeState.hasPropertyChanges() || nodeState.hasRelationshipChanges()
return nodeState.hasRelationshipChanges()
? iteratorRelationshipCursor.get().init( cursor, nodeState.getAddedRelationships( direction, relTypes ) )
: cursor;
}
Expand Down
Expand Up @@ -176,10 +176,11 @@ public boolean next()
reset();
return false;
}

// Check tx state
boolean hasChanges = hasChanges();

TransactionState txs = hasChanges ? read.txState() : null;

do
{
if ( hasChanges && containsNode( txs ) )
Expand Down
Expand Up @@ -252,7 +252,7 @@ else if ( hasDirectFlag( reference ) ) // the relationships for this node are no
public final void relationships(
long nodeReference, long reference, org.neo4j.internal.kernel.api.RelationshipTraversalCursor cursor )
{
/* TODO: There are actually five (5!) different ways a relationship traversal cursor can be initialized:
/* There are 5 different ways a relationship traversal cursor can be initialized:
*
* 1. From a batched group in a detached way. This happens when the user manually retrieves the relationships
* references from the group cursor and passes it to this method and if the group cursor was based on having
Expand Down Expand Up @@ -282,7 +282,8 @@ public final void relationships(
ktx.assertOpen();
if ( reference == NO_ID ) // there are no relationships for this node
{
cursor.close();
// still initiate cursor in case there are tx-state additions
((RelationshipTraversalCursor) cursor).chain( nodeReference, reference, this );
}
else if ( hasGroupFlag( reference ) ) // this reference is actually to a group record
{
Expand Down
Expand Up @@ -19,19 +19,14 @@
*/
package org.neo4j.kernel.impl.newapi;

import java.util.Set;

import org.neo4j.internal.kernel.api.RelationshipDataAccessor;
import org.neo4j.kernel.impl.api.RelationshipVisitor;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;

import static java.util.Collections.emptySet;

abstract class RelationshipCursor extends RelationshipRecord implements RelationshipDataAccessor, RelationshipVisitor<RuntimeException>
{
Read read;
private HasChanges hasChanges = HasChanges.MAYBE;
Set<Long> addedRelationships;

RelationshipCursor()
{
Expand All @@ -42,7 +37,6 @@ protected void init( Read read )
{
this.read = read;
this.hasChanges = HasChanges.MAYBE;
this.addedRelationships = emptySet();
}

@Override
Expand Down Expand Up @@ -99,7 +93,7 @@ public long propertiesReference()
return getNextProp();
}

protected abstract boolean shouldGetAddedTxStateSnapshot();
protected abstract void collectAddedTxStateSnapshot();

/**
* RelationshipCursor should only see changes that are there from the beginning
Expand All @@ -113,10 +107,7 @@ protected boolean hasChanges()
boolean changes = read.hasTxStateWithChanges();
if ( changes )
{
if ( shouldGetAddedTxStateSnapshot() )
{
addedRelationships = read.txState().addedAndRemovedRelationships().getAddedSnapshot();
}
collectAddedTxStateSnapshot();
hasChanges = HasChanges.YES;
}
else
Expand Down
Expand Up @@ -19,15 +19,20 @@
*/
package org.neo4j.kernel.impl.newapi;

import java.util.Set;

import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.kernel.api.txstate.TransactionState;

import static java.util.Collections.emptySet;

class RelationshipScanCursor extends RelationshipCursor implements org.neo4j.internal.kernel.api.RelationshipScanCursor
{
private int label;
private long next;
private long highMark;
private PageCursor pageCursor;
Set<Long> addedRelationships;

void scan( int label, Read read )
{
Expand All @@ -43,6 +48,7 @@ void scan( int label, Read read )
this.label = label;
highMark = read.relationshipHighMark();
init( read );
this.addedRelationships = emptySet();
}

void single( long reference, Read read )
Expand All @@ -59,6 +65,7 @@ void single( long reference, Read read )
label = -1;
highMark = NO_ID;
init( read );
this.addedRelationships = emptySet();
}

@Override
Expand Down Expand Up @@ -172,8 +179,11 @@ private boolean isSingle()
return highMark == NO_ID;
}

protected boolean shouldGetAddedTxStateSnapshot()
protected void collectAddedTxStateSnapshot()
{
return !isSingle();
if ( !isSingle() )
{
addedRelationships = read.txState().addedAndRemovedRelationships().getAddedSnapshot();
}
}
}

0 comments on commit 573c5a3

Please sign in to comment.