diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala index d19b04a680350..8ce55efd5314c 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v2_3/TransactionBoundQueryContext.scala @@ -716,7 +716,7 @@ final class TransactionBoundQueryContext(tc: TransactionalContextWrapper, val re def addIndexRule(labelId: Int, propertyKeyId: Int): IdempotentResult[SchemaTypes.IndexDescriptor] = try { IdempotentResult( DefaultIndexReference.toDescriptor( - tc.kernelTransaction.schemaWrite().indexCreate(SchemaDescriptorFactory.forLabel(labelId, propertyKeyId), null)) + tc.kernelTransaction.schemaWrite().indexCreate(SchemaDescriptorFactory.forLabel(labelId, propertyKeyId))) ) } catch { case _: AlreadyIndexedException => diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_1/TransactionBoundQueryContext.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_1/TransactionBoundQueryContext.scala index e83cd35f5f327..859f659d4ae6f 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_1/TransactionBoundQueryContext.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/spi/v3_1/TransactionBoundQueryContext.scala @@ -731,7 +731,7 @@ final class TransactionBoundQueryContext(txContext: TransactionalContextWrapper, override def addIndexRule(labelId: Int, propertyKeyId: Int): IdempotentResult[IndexDescriptor] = try { IdempotentResult( DefaultIndexReference.toDescriptor( - txContext.kernelTransaction.schemaWrite().indexCreate(SchemaDescriptorFactory.forLabel(labelId, propertyKeyId), null)) + txContext.kernelTransaction.schemaWrite().indexCreate(SchemaDescriptorFactory.forLabel(labelId, propertyKeyId))) ) } catch { case _: AlreadyIndexedException => diff --git a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala index 75c4796558928..77e899cdf6567 100644 --- a/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala +++ b/community/cypher/interpreted-runtime/src/main/scala/org/neo4j/cypher/internal/runtime/interpreted/TransactionBoundQueryContext.scala @@ -640,7 +640,7 @@ sealed class TransactionBoundQueryContext(val transactionalContext: Transactiona override def addIndexRule(descriptor: IndexDescriptor): IdempotentResult[IndexReference] = { val kernelDescriptor = cypherToKernelSchema(descriptor) try { - IdempotentResult(transactionalContext.kernelTransaction.schemaWrite().indexCreate(kernelDescriptor, null)) + IdempotentResult(transactionalContext.kernelTransaction.schemaWrite().indexCreate(kernelDescriptor)) } catch { case _: AlreadyIndexedException => val indexReference = transactionalContext.kernelTransaction.schemaRead().index(kernelDescriptor.getLabelId, kernelDescriptor.getPropertyIds: _*) 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 0593a8ca9670f..b8a0acdf733e1 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 @@ -30,6 +30,16 @@ */ public interface SchemaWrite { + /** + * Create index from schema descriptor. Default configured index provider will be used. + * + * @param descriptor description of the index + */ + default IndexReference indexCreate( SchemaDescriptor descriptor ) throws SchemaKernelException + { + return indexCreate( descriptor, null ); + } + /** * Create index from schema descriptor. Optionally a specific provider name can be specified. * @@ -47,18 +57,42 @@ public interface SchemaWrite void indexDrop( IndexReference index ) throws SchemaKernelException; /** - * Create unique property constraint + * Create unique property constraint. Default configured index provider will be used. * * @param descriptor description of the constraint */ - ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor descriptor ) throws SchemaKernelException; + default ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor descriptor ) throws SchemaKernelException + { + return uniquePropertyConstraintCreate( descriptor, null ); + } /** - * Create node key constraint + * Create unique property constraint. Optionally a specific provider name can be specified. * * @param descriptor description of the constraint + * @param providerName specific index provider this index will be created for. If {@code null} then the default configured will be used. + * @return the newly created index + */ + ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor descriptor, String providerName ) throws SchemaKernelException; + + /** + * Create node key constraint. Default configured index provider will be used. + * + * @param descriptor description of the constraint + */ + default ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descriptor ) throws SchemaKernelException + { + return nodeKeyConstraintCreate( descriptor, null ); + } + + /** + * Create node key constraint. Optionally a specific provider name can be specified. + * + * @param descriptor description of the constraint + * @param providerName specific index provider this index will be created for. If {@code null} then the default configured will be used. + * @return the newly created index */ - ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descriptor ) throws SchemaKernelException; + ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descriptor, String providerName ) throws SchemaKernelException; /** * Create node property existence constraint diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java index 0f1fa46f78cec..0e6ea7f20f01d 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/TransactionState.java @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.api.txstate; +import javax.annotation.Nullable; + import org.neo4j.internal.kernel.api.schema.SchemaDescriptor; import org.neo4j.internal.kernel.api.schema.constraints.ConstraintDescriptor; import org.neo4j.kernel.api.index.IndexProvider; @@ -85,7 +87,7 @@ public interface TransactionState extends ReadableTransactionState * @param providerDescriptor specific {@link IndexProvider.Descriptor} to use for this index to be created. * This provider descriptor is allowed to be null, which will be interpreted as simply using the default instead. */ - void indexRuleDoAdd( SchemaIndexDescriptor descriptor, IndexProvider.Descriptor providerDescriptor ); + void indexRuleDoAdd( SchemaIndexDescriptor descriptor, @Nullable IndexProvider.Descriptor providerDescriptor ); void indexDoDrop( SchemaIndexDescriptor descriptor ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderDescriptorByName.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderDescriptorByName.java deleted file mode 100644 index 0c13f6fdabc93..0000000000000 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderDescriptorByName.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.index; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.function.Consumer; - -import org.neo4j.kernel.api.index.IndexProvider; - -/** - * Can visit an {@link IndexProviderMap} and extract {@link IndexProvider.Descriptor} matching a given name. - */ -public class IndexProviderDescriptorByName implements Consumer, Iterable -{ - private final Set hits = new HashSet<>(); - private final String name; - - public IndexProviderDescriptorByName( String name ) - { - this.name = name; - } - - @Override - public void accept( IndexProvider indexProvider ) - { - IndexProvider.Descriptor providerDescriptor = indexProvider.getProviderDescriptor(); - if ( providerDescriptor.name().equals( name ) ) - { - hits.add( providerDescriptor ); - } - } - - @Override - public Iterator iterator() - { - return hits.iterator(); - } - - public IndexProvider.Descriptor single() - { - Iterator iterator = hits.iterator(); - if ( !iterator.hasNext() ) - { - throw new IllegalArgumentException( "No index provider matching name '" + name + "'" ); - } - IndexProvider.Descriptor single = iterator.next(); - if ( iterator.hasNext() ) - { - throw new IllegalArgumentException( "Multiple index providers matching name '" + name + "'" ); - } - return single; - } -} diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderMap.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderMap.java index 68cb1b6341caa..5ca7d54c24dcb 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderMap.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/index/IndexProviderMap.java @@ -27,7 +27,9 @@ public interface IndexProviderMap extends Function { @Override - IndexProvider apply( IndexProvider.Descriptor descriptor ) throws IndexProviderNotFoundException; + IndexProvider apply( IndexProvider.Descriptor providerDescriptor ) throws IndexProviderNotFoundException; + + IndexProvider apply( String providerDescriptorName ) throws IndexProviderNotFoundException; IndexProvider getDefaultProvider(); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java index 2dc6b6ecc3f92..0447c02a08c9e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/ConstraintIndexCreator.java @@ -42,12 +42,14 @@ import org.neo4j.kernel.api.exceptions.schema.AlreadyIndexedException; import org.neo4j.kernel.api.exceptions.schema.CreateConstraintFailureException; import org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException; +import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.index.PropertyAccessor; import org.neo4j.kernel.api.schema.constaints.ConstraintDescriptorFactory; import org.neo4j.kernel.api.schema.constaints.UniquenessConstraintDescriptor; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptor.Type; import org.neo4j.kernel.api.schema.index.SchemaIndexDescriptorFactory; +import org.neo4j.kernel.api.txstate.TransactionState; import org.neo4j.kernel.impl.api.KernelTransactionImplementation; import org.neo4j.kernel.impl.api.index.IndexProxy; import org.neo4j.kernel.impl.api.index.IndexingService; @@ -91,9 +93,11 @@ public ConstraintIndexCreator( Supplier kernelSupplier, IndexingService *
  • Leave this method, knowing that the uniqueness constraint rule will be added to tx state * and this tx committed, which will create the uniqueness constraint
  • * + * + * Btw providerDescriptor is allowed to be null, where default configured will be used. */ public long createUniquenessConstraintIndex( KernelTransactionImplementation transaction, - SchemaDescriptor descriptor ) throws TransactionFailureException, CreateConstraintFailureException, + SchemaDescriptor descriptor, IndexProvider.Descriptor providerDescriptor ) throws TransactionFailureException, CreateConstraintFailureException, UniquePropertyValueValidationException, AlreadyConstrainedException { UniquenessConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForSchema( descriptor ); @@ -102,7 +106,7 @@ public long createUniquenessConstraintIndex( KernelTransactionImplementation tra SchemaRead schemaRead = transaction.schemaRead(); try { - index = getOrCreateUniquenessConstraintIndex( schemaRead, transaction.tokenRead(), descriptor ); + index = getOrCreateUniquenessConstraintIndex( schemaRead, transaction.tokenRead(), descriptor, providerDescriptor ); } catch ( AlreadyConstrainedException e ) { @@ -242,7 +246,7 @@ private void awaitConstrainIndexPopulation( UniquenessConstraintDescriptor const } private CapableIndexReference getOrCreateUniquenessConstraintIndex( SchemaRead schemaRead, - TokenRead tokenRead, SchemaDescriptor schema ) + TokenRead tokenRead, SchemaDescriptor schema, IndexProvider.Descriptor providerDescriptor ) throws SchemaKernelException, IndexNotFoundKernelException { CapableIndexReference descriptor = schemaRead.index( schema.keyId(), schema.getPropertyIds() ); @@ -265,21 +269,22 @@ private CapableIndexReference getOrCreateUniquenessConstraintIndex( SchemaRead s // There's already an index for this schema descriptor, which isn't of the type we're after. throw new AlreadyIndexedException( schema, CONSTRAINT_CREATION ); } - SchemaIndexDescriptor indexDescriptor = createConstraintIndex( schema ); + SchemaIndexDescriptor indexDescriptor = createConstraintIndex( schema, providerDescriptor ); IndexProxy indexProxy = indexingService.getIndexProxy( indexDescriptor.schema() ); return new DefaultCapableIndexReference( indexDescriptor.type() == Type.UNIQUE, indexProxy.getIndexCapability(), indexProxy.getProviderDescriptor(), indexDescriptor.schema().keyId(), indexDescriptor.schema().getPropertyIds() ); } - public SchemaIndexDescriptor createConstraintIndex( final SchemaDescriptor schema ) + public SchemaIndexDescriptor createConstraintIndex( final SchemaDescriptor schema, IndexProvider.Descriptor providerDescriptor ) { try ( Session session = kernelSupplier.get().beginSession( AUTH_DISABLED ); Transaction transaction = session.beginTransaction( Transaction.Type.implicit ); Statement ignore = ((KernelTransaction)transaction).acquireStatement() ) { SchemaIndexDescriptor index = SchemaIndexDescriptorFactory.uniqueForSchema( schema ); - ((KernelTransactionImplementation) transaction).txState().indexRuleDoAdd( index, null ); + TransactionState transactionState = ((KernelTransactionImplementation) transaction).txState(); + transactionState.indexRuleDoAdd( index, providerDescriptor ); transaction.success(); return index; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java index 133e8975eca7b..9e30160098dbc 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/state/TxState.java @@ -810,6 +810,10 @@ public void indexRuleDoAdd( SchemaIndexDescriptor descriptor, IndexProvider.Desc public void indexDoDrop( SchemaIndexDescriptor descriptor ) { indexChangesDiffSets().remove( descriptor ); + if ( specificIndexProviders != null ) + { + specificIndexProviders.remove( descriptor ); + } changed(); } 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 0d878259f8437..5bb12629c0760 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 @@ -461,7 +461,7 @@ public IndexDefinition createIndexDefinition( Label label, String... propertyKey int labelId = tokenWrite.labelGetOrCreateForName( indexDefinition.getLabel().name() ); int[] propertyKeyIds = getOrCreatePropertyKeyIds( tokenWrite, indexDefinition ); LabelSchemaDescriptor descriptor = forLabel( labelId, propertyKeyIds ); - transaction.schemaWrite().indexCreate( descriptor, null ); + transaction.schemaWrite().indexCreate( descriptor ); return indexDefinition; } 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 c113f471849a9..5fb294ce792c1 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 @@ -82,7 +82,6 @@ import org.neo4j.kernel.api.txstate.ExplicitIndexTransactionState; import org.neo4j.kernel.api.txstate.TransactionState; import org.neo4j.kernel.impl.api.KernelTransactionImplementation; -import org.neo4j.kernel.impl.api.index.IndexProviderDescriptorByName; import org.neo4j.kernel.impl.api.index.IndexProviderMap; import org.neo4j.kernel.impl.api.state.ConstraintIndexCreator; import org.neo4j.kernel.impl.api.store.DefaultIndexReference; @@ -887,16 +886,7 @@ public IndexReference indexCreate( SchemaDescriptor descriptor, String providerN assertIndexDoesNotExist( SchemaKernelException.OperationContext.INDEX_CREATION, descriptor ); SchemaIndexDescriptor indexDescriptor = SchemaIndexDescriptorFactory.forSchema( descriptor ); - IndexProvider.Descriptor providerDescriptor = null; - if ( providerName != null ) - { - IndexProviderDescriptorByName candidates = new IndexProviderDescriptorByName( providerName ); - indexProviderMap.accept( candidates ); - - // We have to have a one-to-one mapping to the specified provider name, otherwise we can't be sure which. - // Having this method fail if that's not the case is OK since that's a user error and way before commit. - providerDescriptor = candidates.single(); - } + IndexProvider.Descriptor providerDescriptor = providerName != null ? indexProviderMap.apply( providerName ).getProviderDescriptor() : null; ktx.txState().indexRuleDoAdd( indexDescriptor, providerDescriptor ); return DefaultIndexReference.fromDescriptor( indexDescriptor ); } @@ -934,7 +924,7 @@ public void indexDrop( IndexReference index ) throws SchemaKernelException } @Override - public ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor descriptor ) + public ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor descriptor, String providerName ) throws SchemaKernelException { //Lock @@ -949,12 +939,13 @@ public ConstraintDescriptor uniquePropertyConstraintCreate( SchemaDescriptor des assertIndexDoesNotExist( SchemaKernelException.OperationContext.CONSTRAINT_CREATION, descriptor ); // Create constraints - indexBackedConstraintCreate( constraint ); + IndexProvider.Descriptor providerDescriptor = providerName != null ? indexProviderMap.apply( providerName ).getProviderDescriptor() : null; + indexBackedConstraintCreate( constraint, providerDescriptor ); return constraint; } @Override - public ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descriptor ) throws SchemaKernelException + public ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descriptor, String providerName ) throws SchemaKernelException { //Lock acquireExclusiveLabelLock( descriptor.getLabelId() ); @@ -975,7 +966,8 @@ public ConstraintDescriptor nodeKeyConstraintCreate( LabelSchemaDescriptor descr } //create constraint - indexBackedConstraintCreate( constraint ); + IndexProvider.Descriptor providerDescriptor = providerName != null ? indexProviderMap.apply( providerName ).getProviderDescriptor() : null; + indexBackedConstraintCreate( constraint, providerDescriptor ); return constraint; } @@ -1204,7 +1196,7 @@ private org.neo4j.kernel.api.schema.LabelSchemaDescriptor labelDescriptor( Index return SchemaDescriptorFactory.forLabel( index.label(), index.properties() ); } - private void indexBackedConstraintCreate( IndexBackedConstraintDescriptor constraint ) + private void indexBackedConstraintCreate( IndexBackedConstraintDescriptor constraint, IndexProvider.Descriptor providerDescriptor ) throws CreateConstraintFailureException { SchemaDescriptor descriptor = constraint.schema(); @@ -1229,7 +1221,7 @@ private void indexBackedConstraintCreate( IndexBackedConstraintDescriptor constr return; } } - long indexId = constraintIndexCreator.createUniquenessConstraintIndex( ktx, descriptor ); + long indexId = constraintIndexCreator.createUniquenessConstraintIndex( ktx, descriptor, providerDescriptor ); if ( !allStoreHolder.constraintExists( constraint ) ) { // This looks weird, but since we release the label lock while awaiting population of the index diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/DefaultIndexProviderMap.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/DefaultIndexProviderMap.java index b35939a91cf15..1833d1b0320f8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/DefaultIndexProviderMap.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/transaction/state/DefaultIndexProviderMap.java @@ -28,11 +28,13 @@ import org.neo4j.kernel.api.index.IndexProvider; import org.neo4j.kernel.api.index.IndexProvider.Descriptor; import org.neo4j.kernel.impl.api.index.IndexProviderMap; +import org.neo4j.kernel.impl.api.index.IndexProviderNotFoundException; public class DefaultIndexProviderMap implements IndexProviderMap { private final IndexProvider defaultIndexProvider; private final Map indexProviders = new HashMap<>(); + private final Map indexProvidersByName = new HashMap<>(); public DefaultIndexProviderMap( IndexProvider defaultIndexProvider ) { @@ -43,12 +45,12 @@ public DefaultIndexProviderMap( IndexProvider defaultIndexProvider, Iterable additionalIndexProviders ) { this.defaultIndexProvider = defaultIndexProvider; - indexProviders.put( defaultIndexProvider.getProviderDescriptor(), defaultIndexProvider ); + put( defaultIndexProvider.getProviderDescriptor(), defaultIndexProvider ); for ( IndexProvider provider : additionalIndexProviders ) { Descriptor providerDescriptor = provider.getProviderDescriptor(); Objects.requireNonNull( providerDescriptor ); - IndexProvider existing = indexProviders.putIfAbsent( providerDescriptor, provider ); + IndexProvider existing = put( providerDescriptor, provider ); if ( existing != null ) { throw new IllegalArgumentException( "Tried to load multiple schema index providers with the same provider descriptor " + @@ -57,6 +59,13 @@ public DefaultIndexProviderMap( IndexProvider defaultIndexProvider, } } + private IndexProvider put( Descriptor providerDescriptor, IndexProvider provider ) + { + IndexProvider existing = indexProviders.putIfAbsent( providerDescriptor, provider ); + indexProvidersByName.put( providerDescriptor.name(), provider ); + return existing; + } + @Override public IndexProvider getDefaultProvider() { @@ -64,17 +73,33 @@ public IndexProvider getDefaultProvider() } @Override - public IndexProvider apply( IndexProvider.Descriptor descriptor ) + public IndexProvider apply( IndexProvider.Descriptor providerDescriptor ) { - IndexProvider provider = indexProviders.get( descriptor ); + IndexProvider provider = indexProviders.get( providerDescriptor ); if ( provider != null ) { return provider; } - throw new IllegalArgumentException( "Tried to get index provider for an existing index with provider " + - descriptor + " whereas available providers in this session being " + indexProviders + - ", and default being " + defaultIndexProvider ); + throw notFound( providerDescriptor ); + } + + @Override + public IndexProvider apply( String providerDescriptorName ) throws IndexProviderNotFoundException + { + IndexProvider provider = indexProvidersByName.get( providerDescriptorName ); + if ( provider != null ) + { + return provider; + } + + throw notFound( providerDescriptorName ); + } + + private IllegalArgumentException notFound( Object key ) + { + return new IllegalArgumentException( "Tried to get index provider for an existing index with provider " + key + + " whereas available providers in this session being " + indexProviders + ", and default being " + defaultIndexProvider ); } @Override diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/constraints/ConstraintIndexCreatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/constraints/ConstraintIndexCreatorTest.java index c119434ea0396..b35a74c6cd5d9 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/constraints/ConstraintIndexCreatorTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/constraints/ConstraintIndexCreatorTest.java @@ -26,6 +26,7 @@ import org.neo4j.internal.kernel.api.CapableIndexReference; import org.neo4j.internal.kernel.api.IndexCapability; +import org.neo4j.internal.kernel.api.IndexReference; import org.neo4j.internal.kernel.api.Kernel; import org.neo4j.internal.kernel.api.Modes; import org.neo4j.internal.kernel.api.SchemaRead; @@ -54,6 +55,7 @@ import org.neo4j.kernel.impl.api.index.IndexingService; import org.neo4j.kernel.impl.api.state.ConstraintIndexCreator; import org.neo4j.kernel.impl.api.store.DefaultCapableIndexReference; +import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.locking.ResourceTypes; import org.neo4j.kernel.impl.locking.SimpleStatementLocks; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; @@ -64,6 +66,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doThrow; @@ -104,7 +107,7 @@ public void shouldCreateIndexInAnotherTransaction() throws Exception new ConstraintIndexCreator( () -> kernel, indexingService, propertyAccessor ); // when - long indexId = creator.createUniquenessConstraintIndex( createTransaction(), descriptor ); + long indexId = creator.createUniquenessConstraintIndex( createTransaction(), descriptor, null ); // then assertEquals( INDEX_ID, indexId ); @@ -142,7 +145,7 @@ public void shouldDropIndexIfPopulationFails() throws Exception KernelTransactionImplementation transaction = createTransaction(); try { - creator.createUniquenessConstraintIndex( transaction, descriptor ); + creator.createUniquenessConstraintIndex( transaction, descriptor, null ); fail( "expected exception" ); } @@ -206,7 +209,7 @@ public void shouldReleaseLabelLockWhileAwaitingIndexPopulation() throws Exceptio // when KernelTransactionImplementation transaction = createTransaction(); - creator.createUniquenessConstraintIndex( transaction, descriptor ); + creator.createUniquenessConstraintIndex( transaction, descriptor, null ); // then verify( transaction.statementLocks().pessimistic() ) @@ -236,7 +239,7 @@ public void shouldReuseExistingOrphanedConstraintIndex() throws Exception // when KernelTransactionImplementation transaction = createTransaction(); - long indexId = creator.createUniquenessConstraintIndex( transaction, descriptor ); + long indexId = creator.createUniquenessConstraintIndex( transaction, descriptor, null ); // then assertEquals( orphanedConstraintIndexId, indexId ); @@ -276,7 +279,7 @@ public void shouldFailOnExistingOwnedConstraintIndex() throws Exception try { KernelTransactionImplementation transaction = createTransaction(); - creator.createUniquenessConstraintIndex( transaction, descriptor ); + creator.createUniquenessConstraintIndex( transaction, descriptor, null ); fail( "Should've failed" ); } catch ( AlreadyConstrainedException e ) @@ -292,6 +295,35 @@ public void shouldFailOnExistingOwnedConstraintIndex() throws Exception verifyNoMoreInteractions( schemaRead ); } + @Test + public void shouldCreateConstraintIndexForSpecifiedProvider() throws Exception + { + // given + IndexingService indexingService = mock( IndexingService.class ); + StubKernel kernel = new StubKernel(); + + long constraintIndexId = 111; + when( schemaRead.indexGetCommittedId( indexReference ) ).thenReturn( constraintIndexId ); + IndexProxy indexProxy = mock( IndexProxy.class ); + when( indexingService.getIndexProxy( constraintIndexId ) ).thenReturn( indexProxy ); + when( indexingService.getIndexProxy( descriptor ) ).thenReturn( indexProxy ); + PropertyAccessor propertyAccessor = mock( PropertyAccessor.class ); + ConstraintIndexCreator creator = new ConstraintIndexCreator( () -> kernel, indexingService, propertyAccessor ); + IndexProvider.Descriptor providerDescriptor = new IndexProvider.Descriptor( "Groovy", "1.2" ); + + // when + KernelTransactionImplementation transaction = createTransaction(); + creator.createUniquenessConstraintIndex( transaction, descriptor, providerDescriptor ); + + // then + assertEquals( 1, kernel.transactions.size() ); + TransactionState transactionState = kernel.transactions.get( 0 ).txState(); + verify( transactionState ).indexRuleDoAdd( SchemaIndexDescriptorFactory.uniqueForSchema( descriptor ), providerDescriptor ); + verify( schemaRead ).index( LABEL_ID, PROPERTY_KEY_ID ); + verify( schemaRead ).indexGetCommittedId( any( IndexReference.class ) ); + verifyNoMoreInteractions( schemaRead ); + } + private class StubKernel implements Kernel, Session { private final List transactions = new ArrayList<>(); 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 6a5a07eaa8580..96393c1381350 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 @@ -181,7 +181,7 @@ public void shouldBeAbleToRemoveAConstraintIndexWithoutOwner() throws Exception PropertyAccessor propertyAccessor = mock( PropertyAccessor.class ); ConstraintIndexCreator creator = new ConstraintIndexCreator( () -> kernel, indexingService, propertyAccessor ); - SchemaIndexDescriptor constraintIndex = creator.createConstraintIndex( descriptor ); + SchemaIndexDescriptor constraintIndex = creator.createConstraintIndex( descriptor, null ); // then Transaction transaction = newTransaction(); assertEquals( emptySet(), asSet( transaction.schemaRead().constraintsGetForLabel( labelId ) ) ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java index 34c390eaebfb1..31f48bc3ababa 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/api/state/TxStateTest.java @@ -312,6 +312,56 @@ public void visitAddedIndex( SchemaIndexDescriptor index, IndexProvider.Descript assertEquals( specificProvider, visitedProviderDescriptor.get() ); } + @Test + public void shouldForgetSpecificallySetIndexProviderDescriptorOnDrop() throws ConstraintValidationException, CreateConstraintFailureException + { + // given + IndexProvider.Descriptor specificProvider = new IndexProvider.Descriptor( "myProvider", "9.9" ); + state.indexRuleDoAdd( indexOn_1_1, specificProvider ); + state.indexDoDrop( indexOn_1_1 ); + state.indexRuleDoAdd( indexOn_1_1, null ); + + // when + MutableBoolean called = new MutableBoolean(); + state.accept( new TxStateVisitor.Adapter() + { + @Override + public void visitAddedIndex( SchemaIndexDescriptor index, IndexProvider.Descriptor providerDescriptor ) + { + assertNull( providerDescriptor ); + called.setTrue(); + } + } ); + + // then + assertTrue( called.booleanValue() ); + } + + @Test + public void shouldSpecificallySetIndexProviderDescriptorOnRecreate() throws ConstraintValidationException, CreateConstraintFailureException + { + // given + IndexProvider.Descriptor specificProvider = new IndexProvider.Descriptor( "myProvider", "9.9" ); + IndexProvider.Descriptor specificProvider2 = new IndexProvider.Descriptor( "myOtherProvider", "7.7" ); + state.indexRuleDoAdd( indexOn_1_1, specificProvider ); + state.indexDoDrop( indexOn_1_1 ); + state.indexRuleDoAdd( indexOn_1_1, specificProvider2 ); + + // when + AtomicReference visitedProviderDescriptor = new AtomicReference<>(); + state.accept( new TxStateVisitor.Adapter() + { + @Override + public void visitAddedIndex( SchemaIndexDescriptor index, IndexProvider.Descriptor providerDescriptor ) + { + visitedProviderDescriptor.set( providerDescriptor ); + } + } ); + + // then + assertEquals( specificProvider2, visitedProviderDescriptor.get() ); + } + @Test public void shouldUseNullForUnspecifiedIndexProviderDescriptor() throws ConstraintValidationException, CreateConstraintFailureException { diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/OperationsLockTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/OperationsLockTest.java index 9924b6735f2e2..f4bf38c637a66 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/OperationsLockTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/newapi/OperationsLockTest.java @@ -465,7 +465,7 @@ public void shouldAcquireSchemaWriteLockBeforeRemovingIndexRule() throws Excepti public void shouldAcquireSchemaWriteLockBeforeCreatingUniquenessConstraint() throws Exception { // given - when( constraintIndexCreator.createUniquenessConstraintIndex( transaction, descriptor ) ).thenReturn( 42L ); + when( constraintIndexCreator.createUniquenessConstraintIndex( transaction, descriptor, null ) ).thenReturn( 42L ); when( storeReadLayer.constraintsGetForSchema( descriptor.schema() ) ).thenReturn( Collections.emptyIterator() ); // when