diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/CapableIndexReference.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/CapableIndexReference.java index 79d69d119169e..648c87d7f29b3 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/CapableIndexReference.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/CapableIndexReference.java @@ -19,10 +19,6 @@ */ package org.neo4j.internal.kernel.api; -import java.util.Iterator; -import java.util.List; - -import org.neo4j.helpers.collection.Iterators; import org.neo4j.values.storable.ValueGroup; /** @@ -79,20 +75,4 @@ public String providerVersion() return null; } }; - - /** - * Sorts indexes by type, returning first GENERAL indexes, followed by UNIQUE. Implementation is not suitable in - * hot path. - * - * @param indexes Indexes to sort - * @return sorted indexes - */ - static Iterator sortByType( Iterator indexes ) - { - List materialized = Iterators.asList( indexes ); - return Iterators.concat( - Iterators.filter( i -> !i.isUnique(), materialized.iterator() ), - Iterators.filter( IndexReference::isUnique, materialized.iterator() ) ); - - } } diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/IndexReference.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/IndexReference.java index 496f3811f79de..f9f7ddeecec53 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/IndexReference.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/IndexReference.java @@ -19,6 +19,10 @@ */ package org.neo4j.internal.kernel.api; +import java.util.Iterator; +import java.util.List; + +import org.neo4j.helpers.collection.Iterators; import org.neo4j.internal.kernel.api.schema.SchemaUtil; import static java.lang.String.format; @@ -44,4 +48,20 @@ default String userDescription( TokenNameLookup tokenNameLookup ) String type = isUnique() ? "UNIQUE" : "GENERAL"; return format( "Index( %s, %s )", type, SchemaUtil.niceProperties( tokenNameLookup, properties() ) ); } + + /** + * Sorts indexes by type, returning first GENERAL indexes, followed by UNIQUE. Implementation is not suitable in + * hot path. + * + * @param indexes Indexes to sort + * @return sorted indexes + */ + static Iterator sortByType( Iterator indexes ) + { + List materialized = Iterators.asList( indexes ); + return Iterators.concat( + Iterators.filter( i -> !i.isUnique(), materialized.iterator() ), + Iterators.filter( IndexReference::isUnique, materialized.iterator() ) ); + + } } diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaRead.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaRead.java index 09aec784f9e7f..22ce0b2236edd 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaRead.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaRead.java @@ -48,14 +48,14 @@ public interface SchemaRead * @param labelId The id of the label which associated indexes you are looking for * @return The indexes associated with the given label */ - Iterator indexesGetForLabel( int labelId ); + Iterator indexesGetForLabel( int labelId ); /** * Returns all indexes used in the database * * @return all indexes used in the database */ - Iterator indexesGetAll(); + Iterator indexesGetAll(); /** * Retrieves the state of an index @@ -64,7 +64,7 @@ public interface SchemaRead * @return The state of the provided index * @throws IndexNotFoundKernelException if the index was not found in the database */ - InternalIndexState indexGetState( CapableIndexReference index ) throws IndexNotFoundKernelException; + InternalIndexState indexGetState( IndexReference index ) throws IndexNotFoundKernelException; /** * Retrives the population progress of the index @@ -73,14 +73,14 @@ public interface SchemaRead * @return The population progress of the given index * @throws IndexNotFoundKernelException if the index was not found in the database */ - PopulationProgress indexGetPopulationProgress( CapableIndexReference index ) throws + PopulationProgress indexGetPopulationProgress( IndexReference index ) throws IndexNotFoundKernelException; /** * Get the index id (the id or the schema rule record) for a committed index * - throws exception for indexes that aren't committed. */ - long indexGetCommittedId( CapableIndexReference index ) throws SchemaKernelException; + long indexGetCommittedId( IndexReference index ) throws SchemaKernelException; /** * Returns the failure description of a failed index. @@ -89,7 +89,7 @@ PopulationProgress indexGetPopulationProgress( CapableIndexReference index ) thr * @return The failure message from the index * @throws IndexNotFoundKernelException if the index was not found in the database */ - String indexGetFailure( CapableIndexReference index ) throws IndexNotFoundKernelException; + String indexGetFailure( IndexReference index ) throws IndexNotFoundKernelException; /** * Finds all constraints for the given schema @@ -134,7 +134,7 @@ PopulationProgress indexGetPopulationProgress( CapableIndexReference index ) thr * Get the owning constraint for a constraint index or null if the index does not have an owning * constraint. */ - Long indexGetOwningUniquenessConstraintId( CapableIndexReference index ); + Long indexGetOwningUniquenessConstraintId( IndexReference index ); /** * Returns schema state for the given key or create a new state if not there diff --git a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaWrite.java b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaWrite.java index d68d06ce77e14..4d11a54e0e25e 100644 --- a/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaWrite.java +++ b/community/kernel-api/src/main/java/org/neo4j/internal/kernel/api/SchemaWrite.java @@ -42,7 +42,7 @@ public interface SchemaWrite * * @param index the index to drop */ - void indexDrop( CapableIndexReference index ) throws SchemaKernelException; + void indexDrop( IndexReference index ) throws SchemaKernelException; /** * Create unique property constraint diff --git a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/SchemaReadWriteTestBase.java b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/SchemaReadWriteTestBase.java index c78142505729c..7849acea7a8dd 100644 --- a/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/SchemaReadWriteTestBase.java +++ b/community/kernel-api/src/test/java/org/neo4j/internal/kernel/api/SchemaReadWriteTestBase.java @@ -63,7 +63,7 @@ public void setUp() throws Exception { schemaWrite.constraintDrop( constraints.next() ); } - Iterator indexes = schemaRead.indexesGetAll(); + Iterator indexes = schemaRead.indexesGetAll(); while ( indexes.hasNext() ) { schemaWrite.indexDrop( indexes.next() ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/builtinprocs/SchemaProcedure.java b/community/kernel/src/main/java/org/neo4j/kernel/builtinprocs/SchemaProcedure.java index 655aaa77d2cc4..3dd1632b25cc7 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/builtinprocs/SchemaProcedure.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/builtinprocs/SchemaProcedure.java @@ -38,7 +38,7 @@ import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.ResourceIterator; import org.neo4j.graphdb.Transaction; -import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.IndexReference; import org.neo4j.internal.kernel.api.Read; import org.neo4j.internal.kernel.api.SchemaRead; import org.neo4j.internal.kernel.api.TokenNameLookup; @@ -84,11 +84,11 @@ public GraphResult buildSchemaGraph() int labelId = tokenRead.nodeLabel( label.name() ); Map properties = new HashMap<>(); - Iterator indexReferences = schemaRead.indexesGetForLabel( labelId ); + Iterator indexReferences = schemaRead.indexesGetForLabel( labelId ); ArrayList indexes = new ArrayList<>(); while ( indexReferences.hasNext() ) { - CapableIndexReference index = indexReferences.next(); + IndexReference index = indexReferences.next(); if ( !index.isUnique() ) { String[] propertyNames = PropertyNameUtils.getPropertyKeys( diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultCapableIndexReference.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultCapableIndexReference.java index 4d25e679c619c..d1bc3df8f58e9 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultCapableIndexReference.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultCapableIndexReference.java @@ -25,10 +25,9 @@ import org.neo4j.internal.kernel.api.IndexCapability; import org.neo4j.internal.kernel.api.IndexOrder; import org.neo4j.internal.kernel.api.IndexValueCapability; -import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.internal.kernel.api.schema.LabelSchemaDescriptor; +import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; -import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptorFactory; import org.neo4j.values.storable.ValueGroup; public class DefaultCapableIndexReference implements CapableIndexReference @@ -131,16 +130,4 @@ public static CapableIndexReference fromDescriptor( SchemaIndexDescriptor descri return new DefaultCapableIndexReference( unique, IndexCapability.NO_CAPABILITY, null, schema.getLabelId(), schema.getPropertyIds() ); } - - public static SchemaIndexDescriptor fromReference( CapableIndexReference index ) - { - if ( index.isUnique() ) - { - return SchemaIndexDescriptorFactory.uniqueForLabel( index.label(), index.properties() ); - } - else - { - return SchemaIndexDescriptorFactory.forLabel( index.label(), index.properties() ); - } - } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultIndexReference.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultIndexReference.java new file mode 100644 index 0000000000000..da14eb3d41331 --- /dev/null +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/store/DefaultIndexReference.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2002-2018 "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 . + */ +package org.neo4j.kernel.impl.api.store; + +import java.util.Arrays; + +import org.neo4j.internal.kernel.api.IndexReference; +import org.neo4j.internal.kernel.api.schema.LabelSchemaDescriptor; +import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; + +public class DefaultIndexReference implements IndexReference +{ + private final boolean unique; + private final int label; + private final int[] properties; + + private DefaultIndexReference( boolean unique, int label, int[] properties ) + { + this.unique = unique; + this.label = label; + this.properties = properties; + } + + @Override + public boolean isUnique() + { + return unique; + } + + @Override + public int label() + { + return label; + } + + @Override + public int[] properties() + { + return properties; + } + + public static IndexReference unique( int label, int...properties ) + { + return new DefaultIndexReference( true, label, properties ); + } + + public static IndexReference general( int label, int...properties ) + { + return new DefaultIndexReference( false, label, properties ); + } + + public static IndexReference fromDescriptor( SchemaIndexDescriptor descriptor ) + { + boolean unique = descriptor.type() == SchemaIndexDescriptor.Type.UNIQUE; + LabelSchemaDescriptor schema = descriptor.schema(); + return new DefaultIndexReference( unique, schema.getLabelId(), schema.getPropertyIds() ); + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + + DefaultIndexReference that = (DefaultIndexReference) o; + return unique == that.unique && label == that.label && Arrays.equals( properties, that.properties ); + } + + @Override + public int hashCode() + { + int result = unique ? 1 : 0; + result = 31 * result + label; + result = 31 * result + Arrays.hashCode( properties ); + return result; + } +} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java index 4af1ae3dd428c..034f5ff6ba62e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/coreapi/schema/SchemaImpl.java @@ -40,6 +40,7 @@ import org.neo4j.graphdb.schema.Schema; import org.neo4j.helpers.collection.Iterables; import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.IndexReference; import org.neo4j.internal.kernel.api.InternalIndexState; import org.neo4j.internal.kernel.api.SchemaRead; import org.neo4j.internal.kernel.api.TokenRead; @@ -72,7 +73,6 @@ import org.neo4j.kernel.api.schema.constaints.NodeKeyConstraintDescriptor; import org.neo4j.kernel.api.schema.constaints.RelExistenceConstraintDescriptor; import org.neo4j.kernel.api.schema.constaints.UniquenessConstraintDescriptor; -import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; import org.neo4j.kernel.impl.api.operations.KeyReadOperations; import org.neo4j.storageengine.api.schema.PopulationProgress; import org.neo4j.storageengine.api.schema.SchemaRule; @@ -119,8 +119,8 @@ public Iterable getIndexes( final Label label ) { return emptyList(); } - Iterator indexes = schemaRead.indexesGetForLabel( labelId ); - addDefinitions( definitions, tokenRead, CapableIndexReference.sortByType( indexes ) ); + Iterator indexes = schemaRead.indexesGetForLabel( labelId ); + addDefinitions( definitions, tokenRead, IndexReference.sortByType( indexes ) ); return definitions; } } @@ -134,13 +134,13 @@ public Iterable getIndexes() { List definitions = new ArrayList<>(); - Iterator indexes = schemaRead.indexesGetAll(); - addDefinitions( definitions, transaction.tokenRead(), CapableIndexReference.sortByType( indexes ) ); + Iterator indexes = schemaRead.indexesGetAll(); + addDefinitions( definitions, transaction.tokenRead(), IndexReference.sortByType( indexes ) ); return definitions; } } - private IndexDefinition descriptorToDefinition( final TokenRead tokenRead, CapableIndexReference index ) + private IndexDefinition descriptorToDefinition( final TokenRead tokenRead, IndexReference index ) { try { @@ -156,7 +156,7 @@ private IndexDefinition descriptorToDefinition( final TokenRead tokenRead, Capab } private void addDefinitions( List definitions, final TokenRead tokenRead, - Iterator indexes ) + Iterator indexes ) { addToCollection( map( index -> descriptorToDefinition( tokenRead, index ), indexes ), diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java index acfb3ff0ec62e..c46f5a588d003 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/AllStoreHolder.java @@ -67,6 +67,7 @@ import org.neo4j.kernel.impl.api.security.OverriddenAccessMode; import org.neo4j.kernel.impl.api.security.RestrictedAccessMode; import org.neo4j.kernel.impl.api.store.DefaultCapableIndexReference; +import org.neo4j.kernel.impl.api.store.DefaultIndexReference; import org.neo4j.kernel.impl.api.store.PropertyUtil; import org.neo4j.kernel.impl.index.ExplicitIndexStore; import org.neo4j.kernel.impl.locking.ResourceTypes; @@ -96,7 +97,7 @@ import static org.neo4j.helpers.collection.Iterators.filter; import static org.neo4j.helpers.collection.Iterators.iterator; import static org.neo4j.helpers.collection.Iterators.singleOrNull; -import static org.neo4j.kernel.impl.api.store.DefaultCapableIndexReference.fromDescriptor; +import static org.neo4j.kernel.impl.api.store.DefaultIndexReference.fromDescriptor; import static org.neo4j.register.Registers.newDoubleLongRegister; import static org.neo4j.storageengine.api.txstate.TxStateVisitor.EMPTY; @@ -301,7 +302,7 @@ public CapableIndexReference index( int label, int... properties ) diffSets.apply( emptyResourceIterator() ) ); if ( fromTxState.hasNext() ) { - return fromDescriptor( fromTxState.next() ); + return DefaultCapableIndexReference.fromDescriptor( fromTxState.next() ); } else { @@ -314,7 +315,7 @@ public CapableIndexReference index( int label, int... properties ) } @Override - public Iterator indexesGetForLabel( int labelId ) + public Iterator indexesGetForLabel( int labelId ) { sharedOptimisticLock( ResourceTypes.LABEL, labelId ); ktx.assertOpen(); @@ -324,11 +325,11 @@ public Iterator indexesGetForLabel( int labelId ) { iterator = ktx.txState().indexDiffSetsByLabel( labelId ).apply( iterator ); } - return Iterators.map( DefaultCapableIndexReference::fromDescriptor, iterator ); + return Iterators.map( DefaultIndexReference::fromDescriptor, iterator ); } @Override - public Iterator indexesGetAll() + public Iterator indexesGetAll() { ktx.assertOpen(); @@ -346,7 +347,7 @@ public Iterator indexesGetAll() } @Override - public InternalIndexState indexGetState( CapableIndexReference index ) throws IndexNotFoundKernelException + public InternalIndexState indexGetState( IndexReference index ) throws IndexNotFoundKernelException { assertValidIndex( index ); sharedOptimisticLock( ResourceTypes.LABEL, index.label() ); @@ -355,7 +356,7 @@ public InternalIndexState indexGetState( CapableIndexReference index ) throws In } @Override - public PopulationProgress indexGetPopulationProgress( CapableIndexReference index ) + public PopulationProgress indexGetPopulationProgress( IndexReference index ) throws IndexNotFoundKernelException { sharedOptimisticLock( ResourceTypes.LABEL, index.label() ); @@ -375,7 +376,7 @@ public PopulationProgress indexGetPopulationProgress( CapableIndexReference inde } @Override - public Long indexGetOwningUniquenessConstraintId( CapableIndexReference index ) + public Long indexGetOwningUniquenessConstraintId( IndexReference index ) { sharedOptimisticLock( ResourceTypes.LABEL, index.label() ); ktx.assertOpen(); @@ -383,7 +384,7 @@ public Long indexGetOwningUniquenessConstraintId( CapableIndexReference index ) } @Override - public long indexGetCommittedId( CapableIndexReference index ) throws SchemaRuleNotFoundException + public long indexGetCommittedId( IndexReference index ) throws SchemaRuleNotFoundException { sharedOptimisticLock( ResourceTypes.LABEL, index.label() ); ktx.assertOpen(); @@ -403,7 +404,7 @@ SchemaIndexDescriptor indexDescriptor( IndexReference index ) } @Override - public String indexGetFailure( CapableIndexReference index ) throws IndexNotFoundKernelException + public String indexGetFailure( IndexReference index ) throws IndexNotFoundKernelException { return storeReadLayer.indexGetFailure( new LabelSchemaDescriptor( index.label(), index.properties() ) ); } @@ -1061,7 +1062,7 @@ private BasicContext populateProcedureContext( SecurityContext procedureSecurity return ctx; } - private void assertValidIndex( CapableIndexReference index ) throws IndexNotFoundKernelException + private void assertValidIndex( IndexReference index ) throws IndexNotFoundKernelException { if ( index == CapableIndexReference.NO_INDEX ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Operations.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Operations.java index 6271de57eec20..ce359ae4ff372 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Operations.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Operations.java @@ -794,7 +794,7 @@ public CapableIndexReference indexCreate( LabelSchemaDescriptor descriptor ) thr } @Override - public void indexDrop( CapableIndexReference index ) throws SchemaKernelException + public void indexDrop( IndexReference index ) throws SchemaKernelException { assertValidIndex( index ); @@ -1124,7 +1124,7 @@ private void indexBackedConstraintCreate( IndexBackedConstraintDescriptor constr } } - private void assertValidIndex( CapableIndexReference index ) throws NoSuchIndexException + private void assertValidIndex( IndexReference index ) throws NoSuchIndexException { if ( index == CapableIndexReference.NO_INDEX ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java index ee810b2d13dea..95c31649b02b5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/Read.java @@ -42,10 +42,13 @@ import org.neo4j.kernel.api.ExplicitIndexHits; import org.neo4j.kernel.api.exceptions.index.IndexNotApplicableKernelException; import org.neo4j.kernel.api.exceptions.index.IndexNotFoundKernelException; +import org.neo4j.kernel.api.exceptions.schema.IndexBrokenKernelException; import org.neo4j.kernel.api.txstate.ExplicitIndexTransactionState; import org.neo4j.kernel.api.txstate.TransactionState; import org.neo4j.kernel.api.txstate.TxStateHolder; import org.neo4j.kernel.impl.api.KernelTransactionImplementation; +import org.neo4j.kernel.impl.locking.LockTracer; +import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.ResourceTypes; import org.neo4j.kernel.impl.store.RecordCursor; import org.neo4j.kernel.impl.store.record.DynamicRecord; @@ -63,6 +66,9 @@ import org.neo4j.values.storable.ValueGroup; import org.neo4j.values.storable.Values; +import static java.lang.String.format; +import static org.neo4j.kernel.impl.locking.ResourceTypes.INDEX_ENTRY; +import static org.neo4j.kernel.impl.locking.ResourceTypes.indexEntryResourceId; import static org.neo4j.kernel.impl.newapi.GroupReferenceEncoding.isRelationship; import static org.neo4j.kernel.impl.newapi.References.clearEncoding; import static org.neo4j.kernel.impl.newapi.RelationshipDirection.INCOMING; @@ -144,6 +150,43 @@ public final void nodeIndexSeek( reader.query( target, indexOrder, query ); } + public final long nodeUniqueIndexSeek( + IndexReference index, + IndexOrder indexOrder, + IndexQuery.ExactPredicate...predicates ) + throws IndexNotApplicableKernelException, IndexNotFoundKernelException, IndexBrokenKernelException + { + assertIndexOnline( index ); + assertPredicatesMatchSchema( index, predicates ); + int labelId = index.label(); + + Locks.Client locks = ktx.statementLocks().optimistic(); + LockTracer lockTracer = ktx.lockTracer(); + long indexEntryId = indexEntryResourceId( labelId, predicates ); + + //First try to find node under a shared lock + //if not found upgrade to exclusive and try again + locks.acquireShared( lockTracer, INDEX_ENTRY, indexEntryId ); + try ( NodeValueIndexCursor cursor = cursors.allocateNodeValueIndexCursor() ) + { + nodeIndexSeek( index, cursor, indexOrder, predicates ); + if ( !cursor.next() ) + { + locks.releaseShared( INDEX_ENTRY, indexEntryId ); + locks.acquireExclusive( lockTracer, INDEX_ENTRY, indexEntryId ); + nodeIndexSeek( index, cursor, indexOrder, predicates ); + if ( cursor.next() ) // we found it under the exclusive lock + { + // downgrade to a shared lock + locks.acquireShared( lockTracer, INDEX_ENTRY, indexEntryId ); + locks.releaseExclusive( INDEX_ENTRY, indexEntryId ); + } + } + + return cursor.nodeReference(); + } + } + @Override public final void nodeIndexScan( IndexReference index, @@ -696,4 +739,37 @@ private void releaseSharedLock( ResourceTypes types, long... ids ) ktx.statementLocks().pessimistic().releaseShared( types, ids ); } + private void assertIndexOnline( IndexReference index ) + throws IndexNotFoundKernelException, IndexBrokenKernelException + { + switch ( indexGetState( index ) ) + { + case ONLINE: + return; + default: + throw new IndexBrokenKernelException( indexGetFailure( index ) ); + } + } + + private void assertPredicatesMatchSchema( IndexReference index, IndexQuery.ExactPredicate[] predicates ) + throws IndexNotApplicableKernelException + { + int[] propertyIds = index.properties(); + if ( propertyIds.length != predicates.length ) + { + throw new IndexNotApplicableKernelException( + format( "The index specifies %d properties, but only %d lookup predicates were given.", + propertyIds.length, predicates.length ) ); + } + for ( int i = 0; i < predicates.length; i++ ) + { + if ( predicates[i].propertyKeyId() != propertyIds[i] ) + { + throw new IndexNotApplicableKernelException( + format( "The index has the property id %d in position %d, but the lookup property id was %d.", + propertyIds[i], i, predicates[i].propertyKeyId() ) ); + } + } + } + } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java index 6ce3b27d23b3d..21515a8837009 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/index/IndexIT.java @@ -36,6 +36,7 @@ import org.neo4j.helpers.collection.Iterables; import org.neo4j.helpers.collection.Iterators; import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.IndexReference; import org.neo4j.internal.kernel.api.SchemaRead; import org.neo4j.internal.kernel.api.SchemaWrite; import org.neo4j.internal.kernel.api.TokenWrite; @@ -61,7 +62,7 @@ import static org.mockito.Mockito.mock; import static org.neo4j.helpers.collection.Iterators.asSet; import static org.neo4j.internal.kernel.api.security.LoginContext.AUTH_DISABLED; -import static org.neo4j.kernel.impl.api.store.DefaultCapableIndexReference.fromDescriptor; +import static org.neo4j.kernel.impl.api.store.DefaultIndexReference.fromDescriptor; public class IndexIT extends KernelIntegrationTest { @@ -149,9 +150,9 @@ public void committedAndTransactionalIndexRulesShouldBeMerged() throws Exception // WHEN KernelTransaction transaction = newTransaction( AUTH_DISABLED ); - CapableIndexReference addedRule = transaction.schemaWrite() + IndexReference addedRule = transaction.schemaWrite() .indexCreate( SchemaDescriptorFactory.forLabel( labelId, 10 ) ); - Set indexRulesInTx = asSet( transaction.schemaRead().indexesGetForLabel( labelId ) ); + Set indexRulesInTx = asSet( transaction.schemaRead().indexesGetForLabel( labelId ) ); commit(); // THEN @@ -307,13 +308,13 @@ public void shouldListAll() throws Exception // given SchemaWrite schemaWrite = schemaWriteInNewTransaction(); CapableIndexReference index1 = schemaWrite.indexCreate( descriptor ); - CapableIndexReference index2 = fromDescriptor( + IndexReference index2 = fromDescriptor( ((IndexBackedConstraintDescriptor) schemaWrite.uniquePropertyConstraintCreate( descriptor2 )).ownedIndexDescriptor()) ; commit(); // then/when SchemaRead schemaRead = newTransaction().schemaRead(); - List indexes = Iterators.asList( schemaRead.indexesGetAll() ); + List indexes = Iterators.asList( schemaRead.indexesGetAll() ); assertThat( indexes, containsInAnyOrder( index1, index2 ) ); commit(); } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/MockStore.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/MockStore.java index d6dcb556893aa..4215720566dd1 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/MockStore.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/MockStore.java @@ -31,6 +31,7 @@ import org.neo4j.collection.primitive.Primitive; import org.neo4j.collection.primitive.PrimitiveLongObjectMap; import org.neo4j.internal.kernel.api.CapableIndexReference; +import org.neo4j.internal.kernel.api.IndexReference; import org.neo4j.internal.kernel.api.InternalIndexState; import org.neo4j.internal.kernel.api.exceptions.ProcedureException; import org.neo4j.internal.kernel.api.exceptions.schema.SchemaKernelException; @@ -576,38 +577,38 @@ public CapableIndexReference index( int label, int... properties ) } @Override - public Iterator indexesGetForLabel( int labelId ) + public Iterator indexesGetForLabel( int labelId ) { throw new UnsupportedOperationException( "not implemented" ); } @Override - public Iterator indexesGetAll() + public Iterator indexesGetAll() { throw new UnsupportedOperationException( "not implemented" ); } @Override - public InternalIndexState indexGetState( CapableIndexReference index ) throws IndexNotFoundKernelException + public InternalIndexState indexGetState( IndexReference index ) throws IndexNotFoundKernelException { throw new UnsupportedOperationException( "not implemented" ); } @Override - public PopulationProgress indexGetPopulationProgress( CapableIndexReference index ) + public PopulationProgress indexGetPopulationProgress( IndexReference index ) throws IndexNotFoundKernelException { throw new UnsupportedOperationException( "not implemented" ); } @Override - public long indexGetCommittedId( CapableIndexReference index ) throws SchemaKernelException + public long indexGetCommittedId( IndexReference index ) throws SchemaKernelException { throw new UnsupportedOperationException( "not implemented" ); } @Override - public String indexGetFailure( CapableIndexReference index ) throws IndexNotFoundKernelException + public String indexGetFailure( IndexReference index ) throws IndexNotFoundKernelException { throw new UnsupportedOperationException( "not implemented" ); } @@ -643,7 +644,7 @@ public Iterator constraintsGetForRelationshipType( int typ } @Override - public Long indexGetOwningUniquenessConstraintId( CapableIndexReference index ) + public Long indexGetOwningUniquenessConstraintId( IndexReference index ) { return null; }