Skip to content

Commit

Permalink
Add support for label scan in the Kernel API implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
thobe authored and fickludd committed Nov 9, 2017
1 parent 569035b commit 9a60fd6
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 12 deletions.
@@ -0,0 +1,88 @@
/*
* 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.internal.kernel.api;

import org.junit.Test;

import org.neo4j.collection.primitive.Primitive;
import org.neo4j.collection.primitive.PrimitiveLongSet;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Transaction;

import static org.neo4j.graphdb.Label.label;
import static org.neo4j.internal.kernel.api.NodeValueIndexCursorTestBase.assertFoundNodes;

public abstract class NodeLabelIndexCursorTestBase<G extends KernelAPIReadTestSupport>
extends KernelAPIReadTestBase<G>
{
@Override
void createTestGraph( GraphDatabaseService graphDb )
{
try ( Transaction tx = graphDb.beginTx() )
{
graphDb.createNode( label( "One" ), label( "First" ) );
graphDb.createNode( label( "Two" ), label( "First" ) );
graphDb.createNode( label( "Three" ), label( "First" ) );
graphDb.createNode( label( "Two" ) );
graphDb.createNode( label( "Three" ) );
graphDb.createNode( label( "Three" ) );

tx.success();
}
}

@Test
public void shouldFindNodesByLabel() throws Exception
{
// given
int one = read.nodeLabel( "One" );
int two = read.nodeLabel( "Two" );
int three = read.nodeLabel( "Three" );
int first = read.nodeLabel( "First" );
try ( NodeLabelIndexCursor cursor = cursors.allocateNodeLabelIndexCursor();
PrimitiveLongSet uniqueIds = Primitive.longSet() )
{
// when
read.nodeLabelScan( one, cursor );

// then
assertFoundNodes( cursor, 1, uniqueIds );

// when
read.nodeLabelScan( two, cursor );

// then
assertFoundNodes( cursor, 2, uniqueIds );

// when
read.nodeLabelScan( three, cursor );

// then
assertFoundNodes( cursor, 3, uniqueIds );

// when
uniqueIds.clear();
read.nodeLabelScan( first, cursor );

// then
assertFoundNodes( cursor, 3, uniqueIds );
}
}
}
Expand Up @@ -222,8 +222,7 @@ public void shouldPerformNumericRangeSearch() throws Exception
int prop = read.propertyKey( "prop" ); int prop = read.propertyKey( "prop" );
IndexReference index = read.index( label, prop ); IndexReference index = read.index( label, prop );
try ( NodeValueIndexCursor node = cursors.allocateNodeValueIndexCursor(); try ( NodeValueIndexCursor node = cursors.allocateNodeValueIndexCursor();
PrimitiveLongSet uniqueIds = Primitive.longSet(); PrimitiveLongSet uniqueIds = Primitive.longSet() )
NodeCursor n = cursors.allocateNodeCursor(); PropertyCursor p = cursors.allocatePropertyCursor() )
{ {
// when // when
uniqueIds.clear(); uniqueIds.clear();
Expand Down Expand Up @@ -273,7 +272,7 @@ public void shouldPerformIndexScan() throws Exception
} }
} }


private static void assertFoundNodes( NodeValueIndexCursor node, int nodes, PrimitiveLongSet uniqueIds ) static void assertFoundNodes( NodeIndexCursor node, int nodes, PrimitiveLongSet uniqueIds )
{ {
for ( int i = 0; i < nodes; i++ ) for ( int i = 0; i < nodes; i++ )
{ {
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/ */
package org.neo4j.kernel.impl.newapi; package org.neo4j.kernel.impl.newapi;


import org.neo4j.internal.kernel.api.LabelSet;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;


public interface IndexCursorProgressor public interface IndexCursorProgressor
Expand All @@ -35,4 +36,13 @@ interface NodeValueCursor


boolean node( long reference, Value[] values ); boolean node( long reference, Value[] values );
} }

interface NodeLabelCursor
{
void initialize( IndexCursorProgressor progressor, boolean providesLabels );

void done();

boolean node( long reference, LabelSet labels );
}
} }
Expand Up @@ -22,37 +22,63 @@
import org.neo4j.internal.kernel.api.LabelSet; import org.neo4j.internal.kernel.api.LabelSet;
import org.neo4j.internal.kernel.api.NodeCursor; import org.neo4j.internal.kernel.api.NodeCursor;


class NodeLabelIndexCursor implements org.neo4j.internal.kernel.api.NodeLabelIndexCursor import static org.neo4j.kernel.impl.store.record.AbstractBaseRecord.NO_ID;

class NodeLabelIndexCursor implements org.neo4j.internal.kernel.api.NodeLabelIndexCursor,
IndexCursorProgressor.NodeLabelCursor
{ {
private final Read read; private final Read read;
private long node;
private LabelSet labels;
private IndexCursorProgressor progressor;


NodeLabelIndexCursor( Read read ) NodeLabelIndexCursor( Read read )
{ {
this.read = read; this.read = read;
} }


@Override
public void initialize( IndexCursorProgressor progressor, boolean providesLabels )
{
this.progressor = progressor;
}

@Override
public boolean node( long reference, LabelSet labels )
{
this.node = reference;
this.labels = labels;
return true;
}

@Override
public void done()
{
close();
}

@Override @Override
public void node( NodeCursor cursor ) public void node( NodeCursor cursor )
{ {
throw new UnsupportedOperationException( "not implemented" ); read.singleNode( node, cursor );
} }


@Override @Override
public long nodeReference() public long nodeReference()
{ {
throw new UnsupportedOperationException( "not implemented" ); return node;
} }


@Override @Override
public LabelSet labels() public LabelSet labels()
{ {
throw new UnsupportedOperationException( "not implemented" ); return labels;
} }


@Override @Override
public boolean next() public boolean next()
{ {
throw new UnsupportedOperationException( "not implemented" ); return progressor != null && progressor.next();
} }


@Override @Override
Expand All @@ -64,6 +90,8 @@ public boolean shouldRetry()
@Override @Override
public void close() public void close()
{ {
throw new UnsupportedOperationException( "not implemented" ); progressor.close();
node = NO_ID;
labels = null;
} }
} }
@@ -0,0 +1,57 @@
/*
* 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.newapi;

import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.graphdb.Resource;

class NodeLabelIndexProgressor implements IndexCursorProgressor
{
private final PrimitiveLongIterator iterator;
private final NodeLabelCursor target;

NodeLabelIndexProgressor( PrimitiveLongIterator iterator, NodeLabelCursor target )
{
this.iterator = iterator;
this.target = target;
}

@Override
public boolean next()
{
while ( iterator.hasNext() )
{
if ( target.node( iterator.next(), null ) )
{
return true;
}
}
return false;
}

@Override
public void close()
{
if ( iterator instanceof Resource )
{
((Resource) iterator).close();
}
}
}
Expand Up @@ -21,6 +21,7 @@


import java.util.Arrays; import java.util.Arrays;


import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.internal.kernel.api.IndexQuery; import org.neo4j.internal.kernel.api.IndexQuery;
import org.neo4j.internal.kernel.api.Scan; import org.neo4j.internal.kernel.api.Scan;
import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
Expand All @@ -32,6 +33,7 @@
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.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.LabelScanReader;
import org.neo4j.values.storable.ArrayValue; import org.neo4j.values.storable.ArrayValue;
import org.neo4j.values.storable.TextValue; import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
Expand Down Expand Up @@ -95,12 +97,12 @@ public final void nodeIndexScan(
indexReader( (IndexReference) index ).scan( (NodeValueIndexCursor) cursor ); indexReader( (IndexReference) index ).scan( (NodeValueIndexCursor) cursor );
} }


abstract IndexReader indexReader( IndexReference index );

@Override @Override
public final void nodeLabelScan( int label, org.neo4j.internal.kernel.api.NodeLabelIndexCursor cursor ) public final void nodeLabelScan( int label, org.neo4j.internal.kernel.api.NodeLabelIndexCursor cursor )
{ {
throw new UnsupportedOperationException( "not implemented" ); LabelScanReader reader = labelScanReader();
IndexCursorProgressor.NodeLabelCursor target = (NodeLabelIndexCursor) cursor;
target.initialize( new NodeLabelIndexProgressor( reader.nodesWithLabel( label ), target ), false );
} }


@Override @Override
Expand Down Expand Up @@ -256,6 +258,10 @@ public final void futureRelationshipPropertyReferenceRead( long reference )
{ {
} }


abstract IndexReader indexReader( IndexReference index );

abstract LabelScanReader labelScanReader();

@Override @Override
public abstract IndexReference index( int label, int... properties ); public abstract IndexReference index( int label, int... properties );


Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;


import org.neo4j.collection.primitive.PrimitiveLongIterator;
import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException;
import org.neo4j.kernel.api.schema.LabelSchemaDescriptor; import org.neo4j.kernel.api.schema.LabelSchemaDescriptor;
Expand All @@ -47,6 +48,7 @@
import org.neo4j.storageengine.api.StorageStatement; import org.neo4j.storageengine.api.StorageStatement;
import org.neo4j.storageengine.api.StoreReadLayer; import org.neo4j.storageengine.api.StoreReadLayer;
import org.neo4j.storageengine.api.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.LabelScanReader;
import org.neo4j.string.UTF8; import org.neo4j.string.UTF8;
import org.neo4j.values.storable.ArrayValue; import org.neo4j.values.storable.ArrayValue;
import org.neo4j.values.storable.TextValue; import org.neo4j.values.storable.TextValue;
Expand Down Expand Up @@ -90,6 +92,12 @@ IndexReader indexReader( IndexReference index )
} }
} }


@Override
LabelScanReader labelScanReader()
{
return statement.getLabelScanReader();
}

@Override @Override
public IndexReference index( int label, int... properties ) public IndexReference index( int label, int... properties )
{ {
Expand Down
Expand Up @@ -38,6 +38,7 @@
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.schema.IndexReader; import org.neo4j.storageengine.api.schema.IndexReader;
import org.neo4j.storageengine.api.schema.LabelScanReader;
import org.neo4j.values.storable.ArrayValue; import org.neo4j.values.storable.ArrayValue;
import org.neo4j.values.storable.TextValue; import org.neo4j.values.storable.TextValue;
import org.neo4j.values.storable.Value; import org.neo4j.values.storable.Value;
Expand Down Expand Up @@ -65,6 +66,12 @@ IndexReader indexReader( IndexReference index )
throw new UnsupportedOperationException( "not implemented" ); throw new UnsupportedOperationException( "not implemented" );
} }


@Override
LabelScanReader labelScanReader()
{
throw new UnsupportedOperationException( "not implemented" );
}

@Override @Override
PageCursor nodePage( long reference ) PageCursor nodePage( long reference )
{ {
Expand Down
@@ -0,0 +1,31 @@
/*
* 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.newapi;

import org.neo4j.internal.kernel.api.NodeLabelIndexCursorTestBase;

public class NodeLabelIndexCursorTest extends NodeLabelIndexCursorTestBase<ReadTestSupport>
{
@Override
public ReadTestSupport newTestSupport()
{
return new ReadTestSupport();
}
}

0 comments on commit 9a60fd6

Please sign in to comment.