Skip to content

Commit

Permalink
Simplify StoreSingleNodeCursor
Browse files Browse the repository at this point in the history
Extracting common code patterns into Cursor interfaces
Extract inner classes
Share common code among different classes to avoid duplication
  • Loading branch information
davidegrohmann committed Jan 9, 2017
1 parent dd67bd8 commit 621625a
Show file tree
Hide file tree
Showing 8 changed files with 518 additions and 316 deletions.
Expand Up @@ -139,10 +139,7 @@ public Cursor<LabelItem> label( int labelId )
@Override @Override
public boolean hasLabel( int labelId ) public boolean hasLabel( int labelId )
{ {
try ( Cursor<LabelItem> labelCursor = label( labelId ) ) return label( labelId ).exists();
{
return labelCursor.next();
}
} }


@Override @Override
Expand Down
@@ -0,0 +1,104 @@
/*
* 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.kernel.impl.store.InvalidRecordException;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.NodeRecord;
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 static org.neo4j.kernel.impl.store.record.RecordLoad.CHECK;
import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;

public interface DegreeCounter
{
default long countByFirstPrevPointer( long relationshipId, RecordCursor<RelationshipRecord> cursor,
NodeRecord nodeRecord, RelationshipRecord relationshipRecord )
{
if ( relationshipId == Record.NO_NEXT_RELATIONSHIP.intValue() )
{
return 0;
}
cursor.next( relationshipId, relationshipRecord, FORCE );
if ( relationshipRecord.getFirstNode() == nodeRecord.getId() )
{
return relationshipRecord.getFirstPrevRel();
}
if ( relationshipRecord.getSecondNode() == nodeRecord.getId() )
{
return relationshipRecord.getSecondPrevRel();
}
throw new InvalidRecordException( "Node " + nodeRecord.getId() + " neither start nor end node of " + relationshipRecord );
}

default int countRelationshipsInGroup( long groupId, Direction direction, Integer type, NodeRecord nodeRecord,
RelationshipRecord relationshipRecord, RelationshipGroupRecord groupRecord, RecordCursors cursors )
{
int count = 0;
while ( groupId != Record.NO_NEXT_RELATIONSHIP.intValue() )
{
boolean groupRecordInUse = cursors.relationshipGroup().next( groupId, groupRecord, FORCE );
if ( groupRecordInUse && ( type == null || groupRecord.getType() == type ) )
{
count += nodeDegreeByDirection( direction, nodeRecord, relationshipRecord, groupRecord, cursors );
if ( type != null )
{
// we have read the only type we were interested on, so break the look
break;
}
}
groupId = groupRecord.getNext();
}
return count;
}

default long nodeDegreeByDirection( Direction direction, NodeRecord nodeRecord,
RelationshipRecord relationshipRecord, RelationshipGroupRecord groupRecord, RecordCursors cursors )
{
RecordCursor<RelationshipRecord> cursor = cursors.relationship();
long loopCount = countByFirstPrevPointer( groupRecord.getFirstLoop(), cursor, nodeRecord, relationshipRecord );
switch ( direction )
{
case OUTGOING:
{
long firstOut = groupRecord.getFirstOut();
return countByFirstPrevPointer( firstOut, cursor, nodeRecord, relationshipRecord ) + loopCount;
}
case INCOMING:
{
long firstIn = groupRecord.getFirstIn();
return countByFirstPrevPointer( firstIn, cursor, nodeRecord, relationshipRecord ) + loopCount;
}
case BOTH:
{
long firstOut = groupRecord.getFirstOut();
long firstIn = groupRecord.getFirstIn();
return countByFirstPrevPointer( firstOut, cursor, nodeRecord, relationshipRecord ) +
countByFirstPrevPointer( firstIn, cursor, nodeRecord, relationshipRecord ) + loopCount;
}
default:
throw new IllegalArgumentException( direction.name() );
}
}
}
@@ -0,0 +1,92 @@
/*
* 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.PrimitiveIntIterator;
import org.neo4j.collection.primitive.PrimitiveIntObjectMap;
import org.neo4j.cursor.Cursor;
import org.neo4j.storageengine.api.DegreeItem;

class DegreeItemCursor implements Cursor<DegreeItem>, DegreeItem
{
private final PrimitiveIntObjectMap<int[]> degrees;
private PrimitiveIntIterator keys;

private int type;
private int outgoing;
private int incoming;

DegreeItemCursor( PrimitiveIntObjectMap<int[]> degrees )
{
this.keys = degrees.iterator();
this.degrees = degrees;
}

@Override
public void close()
{
keys = null;
}

@Override
public int type()
{
return type;
}

@Override
public long outgoing()
{
return outgoing;
}

@Override
public long incoming()
{
return incoming;
}

@Override
public DegreeItem get()
{
if ( keys == null )
{
throw new IllegalStateException();
}

return this;
}

@Override
public boolean next()
{
if ( keys != null && keys.hasNext() )
{
type = keys.next();
int[] degreeValues = degrees.get( type );
outgoing = degreeValues[0] + degreeValues[2];
incoming = degreeValues[1] + degreeValues[2];

return true;
}
keys = null;
return false;
}
}
@@ -0,0 +1,113 @@
/*
* 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.cursor.Cursor;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.NodeRecord;
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.DegreeItem;

import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;

class DegreeItemDenseCursor implements Cursor<DegreeItem>, DegreeItem, DegreeCounter
{
private final NodeRecord nodeRecord;
private final RelationshipGroupRecord relationshipGroupRecord;
private final RelationshipRecord relationshipRecord;
private final RecordCursors recordCursors;

private long groupId;
private int type;
private long outgoing;
private long incoming;

DegreeItemDenseCursor( long groupId,
NodeRecord nodeRecord,
RelationshipGroupRecord relationshipGroupRecord,
RelationshipRecord relationshipRecord,
RecordCursors recordCursors )
{
this.groupId = groupId;
this.nodeRecord = nodeRecord;
this.relationshipGroupRecord = relationshipGroupRecord;
this.relationshipRecord = relationshipRecord;
this.recordCursors = recordCursors;
}

@Override
public boolean next()
{
while ( groupId != Record.NO_NEXT_RELATIONSHIP.intValue() )
{
boolean groupRecordInUse = recordCursors.relationshipGroup().next( groupId, relationshipGroupRecord, FORCE );
groupId = relationshipGroupRecord.getNext();
if ( groupRecordInUse )
{
this.type = relationshipGroupRecord.getType();

long firstLoop = relationshipGroupRecord.getFirstLoop();
long firstOut = relationshipGroupRecord.getFirstOut();
long firstIn = relationshipGroupRecord.getFirstIn();

RecordCursor<RelationshipRecord> relationshipCursor = recordCursors.relationship();
long loop = countByFirstPrevPointer( firstLoop, relationshipCursor, nodeRecord, relationshipRecord );
this.outgoing =
countByFirstPrevPointer( firstOut, relationshipCursor, nodeRecord, relationshipRecord ) + loop;
this.incoming =
countByFirstPrevPointer( firstIn, relationshipCursor, nodeRecord, relationshipRecord ) + loop;
return true;
}
}
return false;
}

@Override
public void close()
{
}

@Override
public DegreeItem get()
{
return this;
}

@Override
public int type()
{
return type;
}

@Override
public long outgoing()
{
return outgoing;
}

@Override
public long incoming()
{
return incoming;
}
}

0 comments on commit 621625a

Please sign in to comment.