use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class ConstraintEnforcingEntityOperations method validateNoExistingNodeWithExactValues.
private void validateNoExistingNodeWithExactValues(KernelStatement state, UniquenessConstraintDescriptor constraint, ExactPredicate[] propertyValues, long modifiedNode) throws ConstraintValidationException {
try {
NewIndexDescriptor index = constraint.ownedIndexDescriptor();
assertIndexOnline(state, index);
int labelId = index.schema().getLabelId();
state.locks().optimistic().acquireExclusive(state.lockTracer(), INDEX_ENTRY, indexEntryResourceId(labelId, propertyValues));
long existing = entityReadOperations.nodeGetFromUniqueIndexSeek(state, index, propertyValues);
if (existing != NO_SUCH_NODE && existing != modifiedNode) {
throw new UniquePropertyValueValidationException(constraint, VALIDATION, new IndexEntryConflictException(existing, NO_SUCH_NODE, OrderedPropertyValues.of(propertyValues)));
}
} catch (IndexNotFoundKernelException | IndexBrokenKernelException | IndexNotApplicableKernelException e) {
throw new UnableToValidateConstraintException(constraint, e);
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class IntegrityValidatorTest method shouldValidateUniquenessIndexes.
@Test
public void shouldValidateUniquenessIndexes() throws Exception {
// Given
NeoStores store = mock(NeoStores.class);
IndexingService indexes = mock(IndexingService.class);
IntegrityValidator validator = new IntegrityValidator(store, indexes);
UniquenessConstraintDescriptor constraint = ConstraintDescriptorFactory.uniqueForLabel(1, 1);
doThrow(new UniquePropertyValueValidationException(constraint, ConstraintValidationException.Phase.VERIFICATION, new RuntimeException())).when(indexes).validateIndex(2L);
ConstraintRule record = ConstraintRule.constraintRule(1L, constraint, 2L);
// When
try {
validator.validateSchemaRule(record);
fail("Should have thrown integrity error.");
} catch (Exception e) {
// good
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class Operations method validateNoExistingNodeWithExactValues.
/**
* Check so that there is not an existing node with the exact match of label and property
*/
private void validateNoExistingNodeWithExactValues(IndexBackedConstraintDescriptor constraint, PropertyIndexQuery.ExactPredicate[] propertyValues, long modifiedNode) throws UniquePropertyValueValidationException, UnableToValidateConstraintException {
IndexDescriptor index = allStoreHolder.indexGetForName(constraint.getName());
try (FullAccessNodeValueIndexCursor valueCursor = cursors.allocateFullAccessNodeValueIndexCursor(ktx.cursorContext(), memoryTracker);
IndexReaders indexReaders = new IndexReaders(index, allStoreHolder)) {
assertIndexOnline(index);
SchemaDescriptor schema = index.schema();
long[] labelIds = schema.lockingKeys();
if (labelIds.length != 1) {
throw new UnableToValidateConstraintException(constraint, new AssertionError(format("Constraint indexes are not expected to be multi-token indexes, " + "but the constraint %s was referencing an index with the following schema: %s.", constraint.userDescription(token), schema.userDescription(token))), token);
}
// Take a big fat lock, and check for existing node in index
ktx.lockClient().acquireExclusive(ktx.lockTracer(), INDEX_ENTRY, indexEntryResourceId(labelIds[0], propertyValues));
allStoreHolder.nodeIndexSeekWithFreshIndexReader(valueCursor, indexReaders.createReader(), propertyValues);
if (valueCursor.next() && valueCursor.nodeReference() != modifiedNode) {
throw new UniquePropertyValueValidationException(constraint, VALIDATION, new IndexEntryConflictException(valueCursor.nodeReference(), NO_SUCH_NODE, PropertyIndexQuery.asValueTuple(propertyValues)), token);
}
} catch (IndexNotFoundKernelException | IndexBrokenKernelException | IndexNotApplicableKernelException e) {
throw new UnableToValidateConstraintException(constraint, e, token);
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException 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);
}
}
}
}
use of org.neo4j.kernel.api.exceptions.schema.UniquePropertyValueValidationException in project neo4j by neo4j.
the class UniquenessConstraintValidationIT method shouldPreventConflictingDataInSameTransaction.
@Test
void shouldPreventConflictingDataInSameTransaction() throws Exception {
// given
constrainedNode("Label1", "key1", "value1");
KernelTransaction transaction = newTransaction(AnonymousContext.writeToken());
// when
createLabeledNode(transaction, "Label1", "key1", "value2");
try {
createLabeledNode(transaction, "Label1", "key1", "value2");
fail("expected exception");
}// then
catch (UniquePropertyValueValidationException e) {
assertThat(e.getUserMessage(transaction.tokenRead())).contains("`key1` = 'value2'");
}
commit();
}
Aggregations