Skip to content

Commit

Permalink
Support for explicit indexes.
Browse files Browse the repository at this point in the history
More tests needed. In particular for relationship indexes.
  • Loading branch information
thobe authored and fickludd committed Nov 9, 2017
1 parent 9a60fd6 commit 3a12757
Show file tree
Hide file tree
Showing 27 changed files with 623 additions and 117 deletions.
Expand Up @@ -45,7 +45,7 @@ public interface CursorFactory


// manual indexes // manual indexes


NodeManualIndexCursor allocateNodeManualIndexCursor(); NodeExplicitIndexCursor allocateNodeManualIndexCursor();


RelationshipManualIndexCursor allocateRelationshipManualIndexCursor(); RelationshipExplicitIndexCursor allocateRelationshipManualIndexCursor();
} }
Expand Up @@ -19,7 +19,7 @@
*/ */
package org.neo4j.internal.kernel.api; package org.neo4j.internal.kernel.api;


interface ManualIndexCursor interface ExplicitIndexCursor
{ {
int totalExpectedCursorSize(); int totalExpectedCursorSize();


Expand Down
Expand Up @@ -22,6 +22,6 @@
/** /**
* Cursor for accessing manual index nodes. * Cursor for accessing manual index nodes.
*/ */
public interface NodeManualIndexCursor extends NodeIndexCursor, ManualIndexCursor public interface NodeExplicitIndexCursor extends NodeIndexCursor, ExplicitIndexCursor
{ {
} }
Expand Up @@ -19,6 +19,8 @@
*/ */
package org.neo4j.internal.kernel.api; package org.neo4j.internal.kernel.api;


import org.neo4j.values.storable.Value;

/** /**
* Defines the read operations of the Kernel API. * Defines the read operations of the Kernel API.
*/ */
Expand Down Expand Up @@ -122,4 +124,19 @@ public interface Read
int nodeLabel( String name ); int nodeLabel( String name );


int propertyKey( String name ); int propertyKey( String name );

void nodeExplicitIndexLookup( NodeExplicitIndexCursor cursor, String index, String key, Value value );

void nodeExplicitIndexQuery( NodeExplicitIndexCursor cursor, String index, Object query );

void nodeExplicitIndexQuery( NodeExplicitIndexCursor cursor, String index, String key, Object query );

void relationshipExplicitIndexGet(
RelationshipExplicitIndexCursor cursor, String index, String key, Value value, long source, long target );

void relationshipExplicitIndexQuery(
RelationshipExplicitIndexCursor cursor, String index, Object query, long source, long target );

void relationshipExplicitIndexQuery(
RelationshipExplicitIndexCursor cursor, String index, String key, Object query, long source, long target );
} }
Expand Up @@ -22,6 +22,6 @@
/** /**
* Cursor for accessing manual index relationships. * Cursor for accessing manual index relationships.
*/ */
public interface RelationshipManualIndexCursor extends RelationshipIndexCursor, ManualIndexCursor public interface RelationshipExplicitIndexCursor extends RelationshipIndexCursor, ExplicitIndexCursor
{ {
} }
Expand Up @@ -36,6 +36,5 @@ public interface RelationshipIndexCursor extends Cursor


long targetNodeReference(); long targetNodeReference();


// long relationshipReference(); // not sure relationships will have independent references, so exposing this might long relationshipReference(); // will relationships have independent references? exposing it is leakage!
// be leakage.
} }
@@ -0,0 +1,146 @@
/*
* 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.Relationship;
import org.neo4j.graphdb.Transaction;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.neo4j.graphdb.RelationshipType.withName;
import static org.neo4j.values.storable.Values.stringValue;

public abstract class ExplicitIndexCursorTestBase<G extends KernelAPIReadTestSupport>
extends KernelAPIReadTestBase<G>
{
@Override
void createTestGraph( GraphDatabaseService graphDb )
{
try ( Transaction tx = graphDb.beginTx() )
{
graphDb.index().forNodes( "foo" ).add( graphDb.createNode(), "bar", "this is it" );
Relationship edge = graphDb.createNode().createRelationshipTo( graphDb.createNode(), withName( "LALA" ) );
graphDb.index().forRelationships( "rels" ).add( edge, "alpha", "betting on the wrong string" );

tx.success();
}
}

@Test
public void shouldFindNodeByLookup() throws Exception
{
// given
try ( NodeExplicitIndexCursor cursor = cursors.allocateNodeManualIndexCursor();
PrimitiveLongSet nodes = Primitive.longSet() )
{
// when
read.nodeExplicitIndexLookup( cursor, "foo", "bar", stringValue( "this is it" ) );

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

// when
read.nodeExplicitIndexLookup( cursor, "foo", "bar", stringValue( "not that" ) );

// then
assertFoundNodes( cursor, 0, nodes );
}
}

@Test
public void shouldFindNodeByQuery() throws Exception
{
// given
try ( NodeExplicitIndexCursor cursor = cursors.allocateNodeManualIndexCursor();
PrimitiveLongSet nodes = Primitive.longSet() )
{
// when
read.nodeExplicitIndexQuery( cursor, "foo", "bar:this*" );

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

// when
nodes.clear();
read.nodeExplicitIndexQuery( cursor, "foo", "bar", "this*" );

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

// when
read.nodeExplicitIndexQuery( cursor, "foo", "bar:that*" );

// then
assertFoundNodes( cursor, 0, nodes );

// when
read.nodeExplicitIndexQuery( cursor, "foo", "bar", "that*" );

// then
assertFoundNodes( cursor, 0, nodes );
}
}

@Test
public void shouldFindRelationshipByLookup() throws Exception
{
// given
try ( RelationshipExplicitIndexCursor cursor = cursors.allocateRelationshipManualIndexCursor();
PrimitiveLongSet edges = Primitive.longSet() )
{
// when
read.relationshipExplicitIndexGet(
cursor,
"rels",
"alpha",
stringValue( "betting on the wrong string" ),
-1,
-1 );

// then
assertFoundRelationships( cursor, 1, edges );
}
}

static void assertFoundNodes( NodeIndexCursor node, int nodes, PrimitiveLongSet uniqueIds )
{
for ( int i = 0; i < nodes; i++ )
{
assertTrue( "at least " + nodes + " nodes", node.next() );
assertTrue( uniqueIds.add( node.nodeReference() ) );
}
assertFalse( "no more than " + nodes + " nodes", node.next() );
}

static void assertFoundRelationships( RelationshipIndexCursor edge, int edges, PrimitiveLongSet uniqueIds )
{
for ( int i = 0; i < edges; i++ )
{
assertTrue( "at least " + edges + " relationships", edge.next() );
assertTrue( uniqueIds.add( edge.relationshipReference() ) );
}
assertFalse( "no more than " + edges + " relationships", edge.next() );
}
}
Expand Up @@ -27,7 +27,7 @@
import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.Transaction;


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


public abstract class NodeLabelIndexCursorTestBase<G extends KernelAPIReadTestSupport> public abstract class NodeLabelIndexCursorTestBase<G extends KernelAPIReadTestSupport>
extends KernelAPIReadTestBase<G> extends KernelAPIReadTestBase<G>
Expand Down
Expand Up @@ -31,6 +31,7 @@
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.neo4j.graphdb.Label.label; import static org.neo4j.graphdb.Label.label;
import static org.neo4j.internal.kernel.api.ExplicitIndexCursorTestBase.assertFoundNodes;


public abstract class NodeValueIndexCursorTestBase<G extends KernelAPIReadTestSupport> public abstract class NodeValueIndexCursorTestBase<G extends KernelAPIReadTestSupport>
extends KernelAPIReadTestBase<G> extends KernelAPIReadTestBase<G>
Expand Down Expand Up @@ -271,14 +272,4 @@ public void shouldPerformIndexScan() throws Exception
assertFoundNodes( node, 15, uniqueIds ); assertFoundNodes( node, 15, uniqueIds );
} }
} }

static void assertFoundNodes( NodeIndexCursor node, int nodes, PrimitiveLongSet uniqueIds )
{
for ( int i = 0; i < nodes; i++ )
{
assertTrue( "at least " + nodes + " nodes", node.next() );
assertTrue( uniqueIds.add( node.nodeReference() ) );
}
assertFalse( "no more than " + nodes + " nodes", node.next() );
}
} }
Expand Up @@ -148,6 +148,11 @@ public KernelTransactions( StatementLocksFactory statementLocksFactory,
blockNewTransactions(); blockNewTransactions();
} }


public Supplier<ExplicitIndexTransactionState> explicitIndexTxStateSupplier()
{
return explicitIndexTxStateSupplier;
}

public KernelTransaction newInstance( KernelTransaction.Type type, SecurityContext securityContext, long timeout ) public KernelTransaction newInstance( KernelTransaction.Type type, SecurityContext securityContext, long timeout )
{ {
assertCurrentThreadIsNotBlockingNewTransactions(); assertCurrentThreadIsNotBlockingNewTransactions();
Expand Down
Expand Up @@ -71,14 +71,14 @@ public NodeLabelIndexCursor allocateNodeLabelIndexCursor()
} }


@Override @Override
public NodeManualIndexCursor allocateNodeManualIndexCursor() public NodeExplicitIndexCursor allocateNodeManualIndexCursor()
{ {
return new NodeManualIndexCursor( read ); return new NodeExplicitIndexCursor( read );
} }


@Override @Override
public RelationshipManualIndexCursor allocateRelationshipManualIndexCursor() public RelationshipExplicitIndexCursor allocateRelationshipManualIndexCursor()
{ {
return new RelationshipManualIndexCursor( read ); return new RelationshipExplicitIndexCursor( read );
} }
} }
@@ -0,0 +1,53 @@
/*
* 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.kernel.api.ExplicitIndexHits;

class ExplicitIndexProgressor implements IndexCursorProgressor
{
private final ExplicitCursor cursor;
private final ExplicitIndexHits hits;

ExplicitIndexProgressor( ExplicitCursor cursor, ExplicitIndexHits hits )
{
this.cursor = cursor;
this.hits = hits;
}

@Override
public boolean next()
{
while ( hits.hasNext() )
{
if ( cursor.entity( hits.next(), hits.currentScore() ) )
{
return true;
}
}
return false;
}

@Override
public void close()
{
hits.close();
}
}
@@ -0,0 +1,54 @@
/*
* 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;

abstract class IndexCursor
{
private IndexCursorProgressor progressor;

final void initialize( IndexCursorProgressor progressor )
{
this.progressor = progressor;
}

public final void done()
{
close();
}

public final boolean next()
{
return progressor != null && progressor.next();
}

public final boolean shouldRetry()
{
return false;
}

void close()
{
if ( progressor != null )
{
progressor.close();
}
progressor = null;
}
}

0 comments on commit 3a12757

Please sign in to comment.