private List<Long> asList( NodeValueIndexCursor cursor ) { List<Long> list = new ArrayList<>(); while ( cursor.next() ) { list.add( cursor.nodeReference() ); } return list; }
@Test public void shouldHoldSharedIndexLockIfNodeIsExists() throws Exception { // given NodeValueIndexCursor cursor = mock( NodeValueIndexCursor.class ); when( cursor.next() ).thenReturn( true ); when( cursor.nodeReference() ).thenReturn( 42L ); // when long nodeId = LockingNodeUniqueIndexSeek.apply( locks, LockTracer.NONE, () -> cursor, uniqueNodeIndexSeeker, read, index, predicate ); // then assertEquals( 42L, nodeId ); verify( locks ).acquireShared( LockTracer.NONE, INDEX_ENTRY, resourceId ); verifyNoMoreInteractions( locks ); verify( cursor ).close(); }
private void assertResultsInOrder( List<Pair<Long,Value>> expected, NodeValueIndexCursor cursor ) { Comparator<Pair<Long,Value>> comparator = indexOrder == IndexOrder.ASCENDING ? ( a, b ) -> Values.COMPARATOR.compare( a.other(), b.other() ) : ( a, b ) -> Values.COMPARATOR.compare( b.other(), a.other() ); expected.sort( comparator ); Iterator<Pair<Long,Value>> expectedRows = expected.iterator(); while ( cursor.next() && expectedRows.hasNext() ) { Pair<Long, Value> expectedRow = expectedRows.next(); assertThat( cursor.nodeReference(), equalTo( expectedRow.first() ) ); for ( int i = 0; i < cursor.numberOfProperties(); i++ ) { Value value = cursor.propertyValue( i ); assertThat( value, equalTo( expectedRow.other() ) ); } } assertFalse( expectedRows.hasNext() ); assertFalse( cursor.next() ); }
while ( nodes.next() ) found.add( Pair.of( nodes.nodeReference(), nodes.propertyValue( 0 ) ) ); while ( nodes.next() ) foundIds.add( nodes.nodeReference() );
@Test public void shouldHandleNullInIndexSeek() throws KernelException { // GIVEN Read read = mock( Read.class ); IndexReference index = mock( IndexReference.class ); when( index.properties() ).thenReturn( new int[]{42} ); // WHEN NodeValueIndexCursor cursor = CompiledIndexUtils.indexSeek( mock( Read.class ), mock( CursorFactory.class ), index, null ); // THEN verify( read, never() ).nodeIndexSeek( any(), any(), any(), anyBoolean() ); assertFalse( cursor.next() ); } }
private void assertFoundNodesAndValue( NodeValueIndexCursor node, int nodes, MutableLongSet uniqueIds, IndexValueCapability expectValue, boolean indexProvidesValues ) { uniqueIds.clear(); for ( int i = 0; i < nodes; i++ ) { assertTrue( "at least " + nodes + " nodes, was " + uniqueIds.size(), node.next() ); long nodeReference = node.nodeReference(); assertTrue( "all nodes are unique", uniqueIds.add( nodeReference ) ); // Assert has value capability if ( IndexValueCapability.YES.equals( expectValue ) ) { assertTrue( "Value capability said index would have value for " + expectValue + ", but didn't", node.hasValue() ); } // Assert has correct value if ( indexProvidesValues ) { assertTrue( "Index did not provide values", node.hasValue() ); Value storedValue = getPropertyValueFromStore( nodeReference ); assertThat( "has correct value", node.propertyValue( 0 ), is( storedValue ) ); } } assertFalse( "no more than " + nodes + " nodes", node.next() ); }
@Test public void shouldGetAllDoublePropertyValues() throws Exception { int label = token.nodeLabel( "Node" ); int prop = token.propertyKey( "prop" ); int prip = token.propertyKey( "prip" ); IndexReference index = schemaRead.index( label, prop, prip ); try ( NodeValueIndexCursor node = cursors.allocateNodeValueIndexCursor() ) { read.nodeIndexScan( index, node, IndexOrder.NONE, true ); List<ValueTuple> values = new ArrayList<>(); while ( node.next() ) { values.add( ValueTuple.of( node.propertyValue( 0 ), node.propertyValue( 1 ) ) ); } values.sort( ValueTuple.COMPARATOR ); for ( int i = 0; i < doublePropValues.size(); i++ ) { assertEquals( doublePropValues.get( i ), values.get( i ) ); } } } }
@Override public final void nodeIndexSeek( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder, boolean needsValues, IndexQuery... query ) throws IndexNotApplicableKernelException, IndexNotFoundKernelException { ktx.assertOpen(); if ( hasForbiddenProperties( index ) ) { cursor.close(); return; } DefaultNodeValueIndexCursor cursorImpl = (DefaultNodeValueIndexCursor) cursor; IndexReader reader = indexReader( index, false ); cursorImpl.setRead( this ); IndexProgressor.NodeValueClient withFullPrecision = injectFullValuePrecision( cursorImpl, query, reader ); reader.query( withFullPrecision, indexOrder, needsValues, query ); }
@Test public void shouldNotSeeNodeThatWasDeletedInTransaction() throws Exception { long nodeID = createNode(); try ( Transaction ignore = graphDatabaseAPI.beginTx() ) { KernelTransaction ktx = ktx(); ktx.dataWrite().nodeDelete( nodeID ); try ( NodeValueIndexCursor cursor = seek( ktx ) ) { assertFalse( cursor.next() ); } } }
@Test public void shouldGetAllSinglePropertyValues() throws Exception { int label = token.nodeLabel( "Node" ); int prop = token.propertyKey( "prop" ); IndexReference index = schemaRead.index( label, prop ); try ( NodeValueIndexCursor node = cursors.allocateNodeValueIndexCursor() ) { read.nodeIndexScan( index, node, IndexOrder.NONE, true ); List<Value> values = new ArrayList<>(); while ( node.next() ) { values.add( node.propertyValue( 0 ) ); } values.sort( Values.COMPARATOR ); for ( int i = 0; i < singlePropValues.size(); i++ ) { assertEquals( singlePropValues.get( i ), values.get( i ) ); } } }
@Override public final void nodeIndexScan( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder, boolean needsValues ) throws KernelException { ktx.assertOpen(); if ( hasForbiddenProperties( index ) ) { cursor.close(); return; } // for a scan, we simply query for existence of the first property, which covers all entries in an index int firstProperty = index.properties()[0]; DefaultNodeValueIndexCursor cursorImpl = (DefaultNodeValueIndexCursor) cursor; cursorImpl.setRead( this ); indexReader( index, false ).query( cursorImpl, indexOrder, needsValues, IndexQuery.exists( firstProperty ) ); }
source1HasNext = source1.next(); if ( source1HasNext ) target1.add( source1.nodeReference() ); source2HasNext = source2.next(); if ( source2HasNext ) target2.add( source2.nodeReference() ); while ( source1.next() ) target1.add( source1.nodeReference() ); while ( source2.next() ) target2.add( source2.nodeReference() );
@Test public void shouldNotSeeNodeThatHasItsLabelRemovedInTransaction() throws Exception { long nodeID = createNode(); try ( Transaction ignore = graphDatabaseAPI.beginTx() ) { KernelTransaction ktx = ktx(); ktx.dataWrite().nodeRemoveLabel( nodeID, LABEL_ID ); try ( NodeValueIndexCursor cursor = seek( ktx ) ) { assertFalse( cursor.next() ); } } }
@Test public void shouldHoldExclusiveIndexLockIfNodeDoesNotExist() throws Exception { // given NodeValueIndexCursor cursor = mock( NodeValueIndexCursor.class ); when( cursor.next() ).thenReturn( false, false ); when( cursor.nodeReference() ).thenReturn( -1L ); // when long nodeId = LockingNodeUniqueIndexSeek.apply( locks, LockTracer.NONE, () -> cursor, uniqueNodeIndexSeeker, read, index, predicate ); // then assertEquals( -1L, nodeId ); order.verify( locks ).acquireShared( LockTracer.NONE, INDEX_ENTRY, resourceId ); order.verify( locks ).releaseShared( INDEX_ENTRY, resourceId ); order.verify( locks ).acquireExclusive( LockTracer.NONE, INDEX_ENTRY, resourceId ); verifyNoMoreInteractions( locks ); verify( cursor ).close(); } }
@Override public final void nodeIndexSeek( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder, boolean needsValues, IndexQuery... query ) throws IndexNotApplicableKernelException, IndexNotFoundKernelException { ktx.assertOpen(); if ( hasForbiddenProperties( index ) ) { cursor.close(); return; } DefaultNodeValueIndexCursor cursorImpl = (DefaultNodeValueIndexCursor) cursor; IndexReader reader = indexReader( index, false ); cursorImpl.setRead( this ); IndexProgressor.NodeValueClient withFullPrecision = injectFullValuePrecision( cursorImpl, query, reader ); reader.query( withFullPrecision, indexOrder, needsValues, query ); }
private void assertFoundNodesAndNoValue( NodeValueIndexCursor node, int nodes, MutableLongSet uniqueIds ) { uniqueIds.clear(); for ( int i = 0; i < nodes; i++ ) { assertTrue( "at least " + nodes + " nodes, was " + uniqueIds.size(), node.next() ); long nodeReference = node.nodeReference(); assertTrue( "all nodes are unique", uniqueIds.add( nodeReference ) ); // We can't quite assert !node.hasValue() because even tho pure SpatialIndexReader is guaranteed to not return any values, // where null could be used, the generic native index, especially when having composite keys including spatial values it's // more of a gray area and some keys may be spatial, some not and therefore a proper Value[] will be extracted // potentially containing some NO_VALUE values. } assertFalse( "no more than " + nodes + " nodes", node.next() ); }
@Test public void shouldNotSeeNodeThatHasAPropertyRemovedInTransaction() throws Exception { long nodeID = createNode(); try ( Transaction ignore = graphDatabaseAPI.beginTx() ) { KernelTransaction ktx = ktx(); ktx.dataWrite().nodeRemoveProperty( nodeID, index.schema().getPropertyIds()[0] ); try ( NodeValueIndexCursor cursor = seek( ktx ) ) { assertFalse( cursor.next() ); } } }
@Test public void shouldHoldSharedIndexLockIfNodeIsConcurrentlyCreated() throws Exception { // given NodeValueIndexCursor cursor = mock( NodeValueIndexCursor.class ); when( cursor.next() ).thenReturn( false, true ); when( cursor.nodeReference() ).thenReturn( 42L ); // when long nodeId = LockingNodeUniqueIndexSeek.apply( locks, LockTracer.NONE, () -> cursor, uniqueNodeIndexSeeker, read, index, predicate ); // then assertEquals( 42L, nodeId ); order.verify( locks ).acquireShared( LockTracer.NONE, INDEX_ENTRY, resourceId ); order.verify( locks ).releaseShared( INDEX_ENTRY, resourceId ); order.verify( locks ).acquireExclusive( LockTracer.NONE, INDEX_ENTRY, resourceId ); order.verify( locks ).acquireShared( LockTracer.NONE, INDEX_ENTRY, resourceId ); order.verify( locks ).releaseExclusive( INDEX_ENTRY, resourceId ); verifyNoMoreInteractions( locks ); verify( cursor ).close(); }
@Override public final void nodeIndexScan( IndexReference index, NodeValueIndexCursor cursor, IndexOrder indexOrder, boolean needsValues ) throws KernelException { ktx.assertOpen(); if ( hasForbiddenProperties( index ) ) { cursor.close(); return; } // for a scan, we simply query for existence of the first property, which covers all entries in an index int firstProperty = index.properties()[0]; DefaultNodeValueIndexCursor cursorImpl = (DefaultNodeValueIndexCursor) cursor; cursorImpl.setRead( this ); indexReader( index, false ).query( cursorImpl, indexOrder, needsValues, IndexQuery.exists( firstProperty ) ); }
if ( !cursor.next() ) if ( cursor.next() ) // we found it under the exclusive lock return cursor.nodeReference();