Skip to content

Commit

Permalink
Flat all relationships and node relationships cursors
Browse files Browse the repository at this point in the history
By having one cursor handling both txState and reading records from disk
  • Loading branch information
davidegrohmann committed May 8, 2017
1 parent 6d65897 commit 959d5b8
Show file tree
Hide file tree
Showing 18 changed files with 669 additions and 434 deletions.

Large diffs are not rendered by default.

Expand Up @@ -56,7 +56,6 @@
import org.neo4j.kernel.impl.util.diffsets.RelationshipDiffSets;
import org.neo4j.storageengine.api.Direction;
import org.neo4j.storageengine.api.PropertyItem;
import org.neo4j.storageengine.api.RelationshipItem;
import org.neo4j.storageengine.api.StorageProperty;
import org.neo4j.storageengine.api.txstate.DiffSetsVisitor;
import org.neo4j.storageengine.api.txstate.NodeState;
Expand All @@ -67,7 +66,6 @@
import org.neo4j.storageengine.api.txstate.RelationshipState;
import org.neo4j.storageengine.api.txstate.TxStateVisitor;

import static org.neo4j.collection.primitive.PrimitiveLongCollections.toPrimitiveIterator;
import static org.neo4j.helpers.collection.Iterables.map;
import static org.neo4j.kernel.impl.api.PropertyValueComparison.SuperType.NUMBER;
import static org.neo4j.kernel.impl.api.PropertyValueComparison.SuperType.STRING;
Expand Down Expand Up @@ -723,34 +721,6 @@ public PrimitiveIntSet augmentLabels( PrimitiveIntSet labels, NodeState nodeStat
return labels;
}

@Override
public Cursor<RelationshipItem> augmentNodeRelationshipCursor( Cursor<RelationshipItem> cursor,
NodeState nodeState,
Direction direction )
{
return nodeState.hasChanges()
? iteratorRelationshipCursor.get().init( cursor, nodeState.getAddedRelationships( direction ) )
: cursor;
}
@Override
public Cursor<RelationshipItem> augmentNodeRelationshipCursor( Cursor<RelationshipItem> cursor,
NodeState nodeState,
Direction direction,
int[] relTypes )
{
return nodeState.hasChanges()
? iteratorRelationshipCursor.get().init( cursor, nodeState.getAddedRelationships( direction, relTypes ) )
: cursor;
}

@Override
public Cursor<RelationshipItem> augmentRelationshipsGetAllCursor( Cursor<RelationshipItem> cursor )
{
return hasChanges && relationships != null && !relationships.isEmpty()
? iteratorRelationshipCursor.get().init( cursor, toPrimitiveIterator( relationships.getAdded().iterator() ) )
: cursor;
}

@Override
public ReadableDiffSets<Long> nodesWithLabelChanged( int labelId )
{
Expand Down
Expand Up @@ -21,7 +21,6 @@

import java.util.Iterator;
import java.util.function.Function;
import java.util.function.IntPredicate;
import java.util.function.Supplier;

import org.neo4j.collection.primitive.PrimitiveIntIterator;
Expand Down Expand Up @@ -79,15 +78,18 @@
import org.neo4j.storageengine.api.Token;
import org.neo4j.storageengine.api.schema.PopulationProgress;
import org.neo4j.storageengine.api.schema.SchemaRule;
import org.neo4j.storageengine.api.txstate.ReadableTransactionState;

import static org.neo4j.collection.primitive.Primitive.intSet;
import static org.neo4j.function.Predicates.ALWAYS_TRUE_INT;
import static org.neo4j.kernel.impl.api.store.DegreeCounter.countByFirstPrevPointer;
import static org.neo4j.kernel.impl.api.store.DegreeCounter.countRelationshipsInGroup;
import static org.neo4j.kernel.impl.store.record.Record.NO_NEXT_RELATIONSHIP;
import static org.neo4j.kernel.impl.store.record.RecordLoad.CHECK;
import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;
import static org.neo4j.register.Registers.newDoubleLongRegister;
import static org.neo4j.storageengine.api.Direction.BOTH;
import static org.neo4j.storageengine.api.Direction.INCOMING;
import static org.neo4j.storageengine.api.Direction.OUTGOING;

/**
* Default implementation of StoreReadLayer. Delegates to NeoStores and indexes.
Expand Down Expand Up @@ -402,17 +404,17 @@ public RelationshipIterator relationshipsGetAll()

@Override
public Cursor<RelationshipItem> nodeGetRelationships( StorageStatement statement, NodeItem nodeItem,
Direction direction )
Direction direction, ReadableTransactionState state )
{
return nodeGetRelationships( statement, nodeItem, direction, ALWAYS_TRUE_INT );
return nodeGetRelationships( statement, nodeItem, direction, null, state );
}

@Override
public Cursor<RelationshipItem> nodeGetRelationships( StorageStatement statement, NodeItem node,
Direction direction, IntPredicate relTypes )
Direction direction, int[] relTypes, ReadableTransactionState state )
{
return statement.acquireNodeRelationshipCursor( node.isDense(), node.id(), node.nextRelationshipId(), direction,
relTypes );
relTypes, state );
}

@Override
Expand Down Expand Up @@ -556,7 +558,7 @@ public PrimitiveIntSet relationshipTypes( StorageStatement statement, NodeItem n
}
else
{
nodeGetRelationships( statement, node, Direction.BOTH )
nodeGetRelationships( statement, node, BOTH, null )
.forAll( relationship -> set.add( relationship.type() ) );
}
return set;
Expand Down Expand Up @@ -606,7 +608,7 @@ public <T> T getOrCreateSchemaDependantState( Class<T> type, Function<StoreReadL

private void visitNode( StorageStatement statement, NodeItem nodeItem, DegreeVisitor visitor )
{
try ( Cursor<RelationshipItem> relationships = nodeGetRelationships( statement, nodeItem, Direction.BOTH ) )
try ( Cursor<RelationshipItem> relationships = nodeGetRelationships( statement, nodeItem, BOTH, null ) )
{
while ( relationships.next() )
{
Expand Down Expand Up @@ -666,11 +668,11 @@ private Direction directionOf( long nodeId, long relationshipId, long startNode,
{
if ( startNode == nodeId )
{
return endNode == nodeId ? Direction.BOTH : Direction.OUTGOING;
return endNode == nodeId ? BOTH : OUTGOING;
}
if ( endNode == nodeId )
{
return Direction.INCOMING;
return INCOMING;
}
throw new InvalidRecordException(
"Node " + nodeId + " neither start nor end node of relationship " + relationshipId +
Expand Down
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.api.store;

import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.storageengine.api.txstate.ReadableTransactionState;

import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_NODE;
import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_RELATIONSHIP;
import static org.neo4j.kernel.api.StatementConstants.NO_SUCH_RELATIONSHIP_TYPE;

public abstract class StoreAbstractIteratorRelationshipCursor extends StoreAbstractRelationshipCursor
{
private ReadableTransactionState state;
private PrimitiveLongIterator addedRelationshipIterator;
private boolean fromStore;

StoreAbstractIteratorRelationshipCursor( RelationshipRecord relationshipRecord, RecordCursors cursors,
LockService lockService )
{
super( relationshipRecord, cursors, lockService );
}

protected StoreAbstractIteratorRelationshipCursor init( ReadableTransactionState state,
PrimitiveLongIterator addedRelationshipIterator )
{
this.state = state;
this.addedRelationshipIterator = addedRelationshipIterator;
this.fromStore = true;
return this;
}

@Override
protected final boolean fetchNext()
{
if ( fromStore )
{
while ( doFetchNext() )
{
if ( state != null && state.relationshipIsDeletedInThisTx( id() ) )
{
continue;
}

return true;
}

fromStore = false;
}

if ( state != null && addedRelationshipIterator != null && addedRelationshipIterator.hasNext() )
{
state.getRelationshipState( addedRelationshipIterator.next() ).accept( this );
return true;
}

visit( NO_SUCH_RELATIONSHIP, NO_SUCH_RELATIONSHIP_TYPE, NO_SUCH_NODE, NO_SUCH_NODE );
return false;
}

protected abstract boolean doFetchNext();

@Override
public void close()
{
super.close();
state = null;
addedRelationshipIterator = null;
}
}
Expand Up @@ -20,39 +20,45 @@
package org.neo4j.kernel.impl.api.store;

import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.graphdb.Resource;
import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.kernel.impl.util.InstanceCache;
import org.neo4j.storageengine.api.txstate.ReadableTransactionState;

import static org.neo4j.collection.primitive.PrimitiveLongCollections.toPrimitiveIterator;
import static org.neo4j.kernel.impl.store.record.RecordLoad.CHECK;

/**
* Cursor for iterating a set of relationships.
*/
public class StoreIteratorRelationshipCursor extends StoreAbstractRelationshipCursor
public class StoreIteratorRelationshipCursor extends StoreAbstractIteratorRelationshipCursor
{
private PrimitiveLongIterator iterator;
private final InstanceCache<StoreIteratorRelationshipCursor> instanceCache;

public StoreIteratorRelationshipCursor( RelationshipRecord relationshipRecord,
InstanceCache<StoreIteratorRelationshipCursor> instanceCache,
RecordCursors cursors,
StoreIteratorRelationshipCursor( RelationshipRecord relationshipRecord,
InstanceCache<StoreIteratorRelationshipCursor> instanceCache, RecordCursors cursors,
LockService lockService )
{
super( relationshipRecord, cursors, lockService );
this.instanceCache = instanceCache;
}

public StoreIteratorRelationshipCursor init( PrimitiveLongIterator iterator )
public StoreIteratorRelationshipCursor init( PrimitiveLongIterator iterator, ReadableTransactionState state )
{
super.init( state, addedRelationships( state ) );
this.iterator = iterator;
return this;
}

private PrimitiveLongIterator addedRelationships( ReadableTransactionState state )
{
return state == null ? null : toPrimitiveIterator( state.addedAndRemovedRelationships().getAdded().iterator() );
}

@Override
protected boolean fetchNext()
protected boolean doFetchNext()
{
while ( iterator != null && iterator.hasNext() )
{
Expand Down
Expand Up @@ -22,14 +22,18 @@
import java.util.function.Consumer;
import java.util.function.IntPredicate;

import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.InvalidRecordException;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.kernel.impl.store.record.RelationshipGroupRecord;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.storageengine.api.Direction;
import org.neo4j.storageengine.api.txstate.ReadableTransactionState;

import static org.neo4j.function.Predicates.ALWAYS_TRUE_INT;
import static org.neo4j.function.Predicates.any;
import static org.neo4j.kernel.impl.store.record.Record.NO_NEXT_RELATIONSHIP;
import static org.neo4j.kernel.impl.store.record.Record.NULL_REFERENCE;
import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;
Expand All @@ -39,7 +43,7 @@
* <p/>
* This cursor handles both dense and non-dense nodes as source.
*/
public class StoreNodeRelationshipCursor extends StoreAbstractRelationshipCursor
public class StoreNodeRelationshipCursor extends StoreAbstractIteratorRelationshipCursor
{
private final RelationshipGroupRecord groupRecord;
private final Consumer<StoreNodeRelationshipCursor> instanceCache;
Expand All @@ -64,12 +68,25 @@ public StoreNodeRelationshipCursor( RelationshipRecord relationshipRecord,
this.cursors = cursors;
}

public StoreNodeRelationshipCursor init( boolean isDense,
long firstRelId,
long fromNodeId,
Direction direction,
IntPredicate allowedTypes )
public StoreNodeRelationshipCursor init( boolean isDense, long firstRelId, long fromNodeId, Direction direction,
ReadableTransactionState state )
{
PrimitiveLongIterator addedNodeRelationships = addedNodeRelationships( fromNodeId, direction, null, state );
return init( isDense, firstRelId, fromNodeId, direction, ALWAYS_TRUE_INT, state, addedNodeRelationships );
}

public StoreNodeRelationshipCursor init( boolean isDense, long firstRelId, long fromNodeId, Direction direction,
int[] allowedTypes, ReadableTransactionState state )
{
PrimitiveLongIterator addedNodeRelationships =
addedNodeRelationships( fromNodeId, direction, allowedTypes, state );
return init( isDense, firstRelId, fromNodeId, direction, any( allowedTypes ), state, addedNodeRelationships );
}

private StoreNodeRelationshipCursor init( boolean isDense, long firstRelId, long fromNodeId, Direction direction,
IntPredicate allowedTypes, ReadableTransactionState state, PrimitiveLongIterator addedNodeRelationships )
{
super.init( state, addedNodeRelationships );
this.isDense = isDense;
this.relationshipId = firstRelId;
this.fromNodeId = fromNodeId;
Expand All @@ -90,8 +107,20 @@ public StoreNodeRelationshipCursor init( boolean isDense,
return this;
}

private PrimitiveLongIterator addedNodeRelationships( long fromNodeId, Direction direction,
int[] allowedTypes, ReadableTransactionState state )
{
if ( state == null )
{
return null;
}

return allowedTypes == null ? state.getNodeState( fromNodeId ).getAddedRelationships( direction )
: state.getNodeState( fromNodeId ).getAddedRelationships( direction, allowedTypes );
}

@Override
protected boolean fetchNext()
protected boolean doFetchNext()
{
while ( relationshipId != NO_NEXT_RELATIONSHIP.intValue() )
{
Expand Down Expand Up @@ -274,4 +303,11 @@ boolean matchesDirection( Direction direction )
}

private static final GroupChain[] GROUP_CHAINS = GroupChain.values();

@Override
public String toString()
{
return String
.format( "RelationShipItem[id=%d, type=%d, start=%d, end=%d]", id(), type(), startNode(), endNode() );
}
}

0 comments on commit 959d5b8

Please sign in to comment.