Search in sources :

Example 1 with AlreadyConstrainedException

use of org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException in project neo4j by neo4j.

the class Operations method assertNoBlockingSchemaRulesExists.

private void assertNoBlockingSchemaRulesExists(ConstraintDescriptor constraint) throws EquivalentSchemaRuleAlreadyExistsException, IndexWithNameAlreadyExistsException, ConstraintWithNameAlreadyExistsException, AlreadyConstrainedException, AlreadyIndexedException {
    final String name = constraint.getName();
    if (name == null) {
        throw new IllegalStateException("Expected constraint to always have a name by this point");
    }
    // Equivalent constraint
    final List<ConstraintDescriptor> constraintsWithSameSchema = Iterators.asList(allStoreHolder.constraintsGetForSchema(constraint.schema()));
    for (ConstraintDescriptor constraintWithSameSchema : constraintsWithSameSchema) {
        if (constraint.equals(constraintWithSameSchema) && constraint.getName().equals(constraintWithSameSchema.getName())) {
            throw new EquivalentSchemaRuleAlreadyExistsException(constraintWithSameSchema, CONSTRAINT_CREATION, token);
        }
    }
    // Name conflict with other schema rule
    assertSchemaRuleWithNameDoesNotExist(name);
    // Already constrained
    for (ConstraintDescriptor constraintWithSameSchema : constraintsWithSameSchema) {
        final boolean creatingExistenceConstraint = constraint.type() == ConstraintType.EXISTS;
        final boolean existingIsExistenceConstraint = constraintWithSameSchema.type() == ConstraintType.EXISTS;
        if (creatingExistenceConstraint == existingIsExistenceConstraint) {
            throw new AlreadyConstrainedException(constraintWithSameSchema, CONSTRAINT_CREATION, token);
        }
    }
    // Already indexed
    if (constraint.type() != ConstraintType.EXISTS) {
        Iterator<IndexDescriptor> existingIndexes = allStoreHolder.index(constraint.schema());
        if (existingIndexes.hasNext()) {
            IndexDescriptor existingIndex = existingIndexes.next();
            throw new AlreadyIndexedException(existingIndex.schema(), CONSTRAINT_CREATION, token);
        }
    }
    // is being populated we will end up with two indexes on the same schema.
    if (constraint.isIndexBackedConstraint() && ktx.hasTxStateWithChanges()) {
        for (ConstraintDescriptor droppedConstraint : ktx.txState().constraintsChanges().getRemoved()) {
            // If dropped and new constraint have similar backing index we cannot allow this constraint creation
            if (droppedConstraint.isIndexBackedConstraint() && constraint.schema().equals(droppedConstraint.schema())) {
                throw new UnsupportedOperationException(format("Trying to create constraint '%s' in same transaction as dropping '%s'. " + "This is not supported because they are both backed by similar indexes. " + "Please drop constraint in a separate transaction before creating the new one.", constraint.getName(), droppedConstraint.getName()));
            }
        }
    }
}
Also used : AlreadyIndexedException(org.neo4j.kernel.api.exceptions.schema.AlreadyIndexedException) EquivalentSchemaRuleAlreadyExistsException(org.neo4j.kernel.api.exceptions.schema.EquivalentSchemaRuleAlreadyExistsException) AlreadyConstrainedException(org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException) ConstraintDescriptor(org.neo4j.internal.schema.ConstraintDescriptor) NodeKeyConstraintDescriptor(org.neo4j.internal.schema.constraints.NodeKeyConstraintDescriptor) UniquenessConstraintDescriptor(org.neo4j.internal.schema.constraints.UniquenessConstraintDescriptor) IndexBackedConstraintDescriptor(org.neo4j.internal.schema.constraints.IndexBackedConstraintDescriptor) IndexDescriptor(org.neo4j.internal.schema.IndexDescriptor)

Example 2 with AlreadyConstrainedException

use of org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException in project neo4j by neo4j.

the class ConstraintIndexCreator method createUniquenessConstraintIndex.

/**
 * You MUST hold a label write lock before you call this method.
 * However the label write lock is temporarily released while populating the index backing the constraint.
 * It goes a little like this:
 * <ol>
 * <li>Prerequisite: Getting here means that there's an open schema transaction which has acquired the
 * LABEL WRITE lock.</li>
 * <li>Index schema rule which is backing the constraint is created in a nested mini-transaction
 * which doesn't acquire any locking, merely adds tx state and commits so that the index rule is applied
 * to the store, which triggers the index population</li>
 * <li>Release the LABEL WRITE lock</li>
 * <li>Await index population to complete</li>
 * <li>Acquire the LABEL WRITE lock (effectively blocking concurrent transactions changing
 * data related to this constraint, and it so happens, most other transactions as well) and verify
 * the uniqueness of the built index</li>
 * <li>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</li>
 * </ol>
 */
public IndexDescriptor createUniquenessConstraintIndex(KernelTransactionImplementation transaction, IndexBackedConstraintDescriptor constraint, IndexPrototype prototype) throws TransactionFailureException, CreateConstraintFailureException, UniquePropertyValueValidationException, AlreadyConstrainedException {
    String constraintString = constraint.userDescription(transaction.tokenRead());
    log.info("Starting constraint creation: %s.", constraintString);
    IndexDescriptor index;
    SchemaRead schemaRead = transaction.schemaRead();
    try {
        index = checkAndCreateConstraintIndex(schemaRead, transaction.tokenRead(), constraint, prototype);
    } catch (AlreadyConstrainedException e) {
        throw e;
    } catch (KernelException e) {
        throw new CreateConstraintFailureException(constraint, e);
    }
    boolean success = false;
    boolean reacquiredLabelLock = false;
    Client locks = transaction.lockClient();
    ResourceType keyType = constraint.schema().keyType();
    long[] lockingKeys = constraint.schema().lockingKeys();
    try {
        locks.acquireShared(transaction.lockTracer(), keyType, lockingKeys);
        IndexProxy proxy = indexingService.getIndexProxy(index);
        // Release the LABEL WRITE lock during index population.
        // At this point the integrity of the constraint to be created was checked
        // while holding the lock and the index rule backing the soon-to-be-created constraint
        // has been created. Now it's just the population left, which can take a long time
        locks.releaseExclusive(keyType, lockingKeys);
        awaitConstraintIndexPopulation(constraint, proxy, transaction);
        log.info("Constraint %s populated, starting verification.", constraintString);
        // Index population was successful, but at this point we don't know if the uniqueness constraint holds.
        // Acquire LABEL WRITE lock and verify the constraints here in this user transaction
        // and if everything checks out then it will be held until after the constraint has been
        // created and activated.
        locks.acquireExclusive(transaction.lockTracer(), keyType, lockingKeys);
        reacquiredLabelLock = true;
        try (NodePropertyAccessor propertyAccessor = new DefaultNodePropertyAccessor(transaction.newStorageReader(), transaction.cursorContext(), transaction.memoryTracker())) {
            indexingService.getIndexProxy(index).verifyDeferredConstraints(propertyAccessor);
        }
        log.info("Constraint %s verified.", constraintString);
        success = true;
        return index;
    } catch (IndexNotFoundKernelException e) {
        String indexString = index.userDescription(transaction.tokenRead());
        throw new TransactionFailureException(format("Index (%s) that we just created does not exist.", indexString), e);
    } catch (IndexEntryConflictException e) {
        throw new UniquePropertyValueValidationException(constraint, VERIFICATION, e, transaction.tokenRead());
    } catch (InterruptedException | IOException e) {
        throw new CreateConstraintFailureException(constraint, e);
    } finally {
        if (!success) {
            if (!reacquiredLabelLock) {
                locks.acquireExclusive(transaction.lockTracer(), keyType, lockingKeys);
            }
            if (indexStillExists(schemaRead, index)) {
                dropUniquenessConstraintIndex(index);
            }
        }
    }
}
Also used : UniquePropertyValueValidationException(org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException) SchemaRead(org.neo4j.internal.kernel.api.SchemaRead) ResourceType(org.neo4j.lock.ResourceType) IndexNotFoundKernelException(org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException) IOException(java.io.IOException) IndexDescriptor(org.neo4j.internal.schema.IndexDescriptor) NodePropertyAccessor(org.neo4j.storageengine.api.NodePropertyAccessor) DefaultNodePropertyAccessor(org.neo4j.kernel.impl.transaction.state.storeview.DefaultNodePropertyAccessor) DefaultNodePropertyAccessor(org.neo4j.kernel.impl.transaction.state.storeview.DefaultNodePropertyAccessor) TransactionFailureException(org.neo4j.internal.kernel.api.exceptions.TransactionFailureException) AlreadyConstrainedException(org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException) IndexProxy(org.neo4j.kernel.impl.api.index.IndexProxy) IndexNotFoundKernelException(org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException) IndexPopulationFailedKernelException(org.neo4j.kernel.api.exceptions.index.IndexPopulationFailedKernelException) KernelException(org.neo4j.exceptions.KernelException) Client(org.neo4j.kernel.impl.locking.Locks.Client) IndexEntryConflictException(org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException) CreateConstraintFailureException(org.neo4j.internal.kernel.api.exceptions.schema.CreateConstraintFailureException)

Example 3 with AlreadyConstrainedException

use of org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException in project neo4j by neo4j.

the class AbstractConstraintCreationIT method shouldNotCreateConstraintThatAlreadyExists.

@Test
public void shouldNotCreateConstraintThatAlreadyExists() throws Exception {
    // given
    {
        SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction();
        createConstraint(statement, descriptor);
        commit();
    }
    // when
    try {
        SchemaWriteOperations statement = schemaWriteOperationsInNewTransaction();
        createConstraint(statement, descriptor);
        fail("Should not have validated");
    }// then
     catch (AlreadyConstrainedException e) {
    // good
    }
}
Also used : SchemaWriteOperations(org.neo4j.kernel.api.SchemaWriteOperations) AlreadyConstrainedException(org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException) Test(org.junit.Test)

Example 4 with AlreadyConstrainedException

use of org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException in project neo4j by neo4j.

the class PlainOperationsTest method shouldReleaseAcquiredSchemaWriteLockIfNodePropertyExistenceConstraintCreationFails.

@Test
void shouldReleaseAcquiredSchemaWriteLockIfNodePropertyExistenceConstraintCreationFails() throws Exception {
    // given
    NodeExistenceConstraintDescriptor constraint = existsForSchema(schema);
    storageReaderWithConstraints(constraint);
    int labelId = schema.getLabelId();
    int propertyId = schema.getPropertyId();
    when(tokenHolders.labelTokens().getTokenById(labelId)).thenReturn(new NamedToken("Label", labelId));
    when(tokenHolders.propertyKeyTokens().getTokenById(propertyId)).thenReturn(new NamedToken("prop", labelId));
    // when
    try {
        operations.nodePropertyExistenceConstraintCreate(schema, "constraint name");
        fail("Expected an exception because this schema should already be constrained.");
    } catch (AlreadyConstrainedException ignore) {
    // Good.
    }
    // then
    order.verify(locks).acquireExclusive(LockTracer.NONE, ResourceTypes.LABEL, labelId);
    order.verify(storageReader).constraintsGetForSchema(schema);
    order.verify(locks).releaseExclusive(ResourceTypes.LABEL, labelId);
}
Also used : AlreadyConstrainedException(org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException) NodeExistenceConstraintDescriptor(org.neo4j.internal.schema.constraints.NodeExistenceConstraintDescriptor) NamedToken(org.neo4j.token.api.NamedToken) Test(org.junit.jupiter.api.Test)

Example 5 with AlreadyConstrainedException

use of org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException in project neo4j by neo4j.

the class PlainOperationsTest method shouldReleaseAcquiredSchemaWriteLockIfConstraintCreationFails.

@Test
void shouldReleaseAcquiredSchemaWriteLockIfConstraintCreationFails() throws Exception {
    // given
    UniquenessConstraintDescriptor constraint = uniqueForSchema(schema);
    storageReaderWithConstraints(constraint);
    int labelId = schema.getLabelId();
    int propertyId = schema.getPropertyId();
    when(tokenHolders.labelTokens().getTokenById(labelId)).thenReturn(new NamedToken("Label", labelId));
    when(tokenHolders.propertyKeyTokens().getTokenById(propertyId)).thenReturn(new NamedToken("prop", labelId));
    // when
    try {
        operations.uniquePropertyConstraintCreate(IndexPrototype.uniqueForSchema(schema).withName("constraint name"));
        fail("Expected an exception because this schema should already be constrained.");
    } catch (AlreadyConstrainedException ignore) {
    // Good.
    }
    // then
    order.verify(locks).acquireExclusive(LockTracer.NONE, ResourceTypes.LABEL, labelId);
    order.verify(storageReader).constraintsGetForSchema(schema);
    order.verify(locks).releaseExclusive(ResourceTypes.LABEL, labelId);
}
Also used : AlreadyConstrainedException(org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException) UniquenessConstraintDescriptor(org.neo4j.internal.schema.constraints.UniquenessConstraintDescriptor) NamedToken(org.neo4j.token.api.NamedToken) Test(org.junit.jupiter.api.Test)

Aggregations

AlreadyConstrainedException (org.neo4j.kernel.api.exceptions.schema.AlreadyConstrainedException)9 Test (org.junit.jupiter.api.Test)4 IndexDescriptor (org.neo4j.internal.schema.IndexDescriptor)4 NamedToken (org.neo4j.token.api.NamedToken)4 NodeKeyConstraintDescriptor (org.neo4j.internal.schema.constraints.NodeKeyConstraintDescriptor)3 UniquenessConstraintDescriptor (org.neo4j.internal.schema.constraints.UniquenessConstraintDescriptor)3 TransactionFailureException (org.neo4j.internal.kernel.api.exceptions.TransactionFailureException)2 CreateConstraintFailureException (org.neo4j.internal.kernel.api.exceptions.schema.CreateConstraintFailureException)2 ConstraintDescriptor (org.neo4j.internal.schema.ConstraintDescriptor)2 IndexBackedConstraintDescriptor (org.neo4j.internal.schema.constraints.IndexBackedConstraintDescriptor)2 AlreadyIndexedException (org.neo4j.kernel.api.exceptions.schema.AlreadyIndexedException)2 EquivalentSchemaRuleAlreadyExistsException (org.neo4j.kernel.api.exceptions.schema.EquivalentSchemaRuleAlreadyExistsException)2 UniquePropertyValueValidationException (org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException)2 IOException (java.io.IOException)1 Test (org.junit.Test)1 KernelException (org.neo4j.exceptions.KernelException)1 SchemaRead (org.neo4j.internal.kernel.api.SchemaRead)1 IndexNotFoundKernelException (org.neo4j.internal.kernel.api.exceptions.schema.IndexNotFoundKernelException)1 RelationTypeSchemaDescriptor (org.neo4j.internal.schema.RelationTypeSchemaDescriptor)1 NodeExistenceConstraintDescriptor (org.neo4j.internal.schema.constraints.NodeExistenceConstraintDescriptor)1