use of org.neo4j.internal.kernel.api.exceptions.TransactionFailureException in project neo4j by neo4j.
the class IntegrityValidator method validateSchemaRule.
void validateSchemaRule(SchemaRule schemaRule) throws TransactionFailureException {
Preconditions.checkState(indexValidator != null, "No index validator installed");
KernelVersion currentVersion = neoStores.getMetaDataStore().kernelVersion();
if (currentVersion.isLessThan(VERSION_IN_WHICH_TOKEN_INDEXES_ARE_INTRODUCED)) {
if (schemaRule instanceof IndexDescriptor) {
IndexDescriptor index = (IndexDescriptor) schemaRule;
if (index.isTokenIndex() || isBtreeRelationshipPropertyIndex(index)) {
throw new TransactionFailureException(Status.General.UpgradeRequired, "Index operation on index '%s' not allowed. " + "Required kernel version for this transaction is %s, but actual version was %s.", index, VERSION_IN_WHICH_TOKEN_INDEXES_ARE_INTRODUCED.name(), currentVersion.name());
}
}
}
if (schemaRule instanceof ConstraintDescriptor) {
ConstraintDescriptor constraint = (ConstraintDescriptor) schemaRule;
if (constraint.isIndexBackedConstraint()) {
long ownedIndex = constraint.asIndexBackedConstraint().ownedIndexId();
try {
indexValidator.validateIndex(ownedIndex);
} catch (KernelException e) {
// and have recovery performed. It's the safest bet to avoid loosing data.
throw new TransactionFailureException(Status.Transaction.TransactionValidationFailed, e, "Index validation of " + schemaRule + " failed, specifically for its owned index " + ownedIndex, e);
}
}
}
}
use of org.neo4j.internal.kernel.api.exceptions.TransactionFailureException in project neo4j by neo4j.
the class KernelTransactionImplementation method commitTransaction.
private long commitTransaction() throws KernelException {
boolean success = false;
long txId = READ_ONLY_ID;
TransactionListenersState listenersState = null;
try (CommitEvent commitEvent = transactionEvent.beginCommitEvent()) {
listenersState = eventListeners.beforeCommit(txState, this, storageReader);
if (listenersState != null && listenersState.isFailed()) {
Throwable cause = listenersState.failure();
if (cause instanceof TransientFailureException) {
throw (TransientFailureException) cause;
}
if (cause instanceof Status.HasStatus) {
throw new TransactionFailureException(((Status.HasStatus) cause).status(), cause, cause.getMessage());
}
throw new TransactionFailureException(Status.Transaction.TransactionHookFailed, cause, cause.getMessage());
}
// Convert changes into commands and commit
if (hasChanges()) {
forceThawLocks();
lockClient.prepareForCommit();
// Gather up commands from the various sources
HeapTrackingArrayList<StorageCommand> extractedCommands = HeapTrackingCollections.newArrayList(memoryTracker);
storageEngine.createCommands(extractedCommands, txState, storageReader, commandCreationContext, lockClient, lockTracer(), lastTransactionIdWhenStarted, this::enforceConstraints, cursorContext, memoryTracker);
/* Here's the deal: we track a quick-to-access hasChanges in transaction state which is true
* if there are any changes imposed by this transaction. Some changes made inside a transaction undo
* previously made changes in that same transaction, and so at some point a transaction may have
* changes and at another point, after more changes seemingly,
* the transaction may not have any changes.
* However, to track that "undoing" of the changes is a bit tedious, intrusive and hard to maintain
* and get right.... So to really make sure the transaction has changes we re-check by looking if we
* have produced any commands to add to the logical log.
*/
if (!extractedCommands.isEmpty()) {
// Finish up the whole transaction representation
PhysicalTransactionRepresentation transactionRepresentation = new PhysicalTransactionRepresentation(extractedCommands);
long timeCommitted = clocks.systemClock().millis();
transactionRepresentation.setHeader(EMPTY_BYTE_ARRAY, startTimeMillis, lastTransactionIdWhenStarted, timeCommitted, leaseClient.leaseId(), securityContext.subject());
// Commit the transaction
success = true;
TransactionToApply batch = new TransactionToApply(transactionRepresentation, cursorContext);
kernelTransactionMonitor.beforeApply();
txId = commitProcess.commit(batch, commitEvent, INTERNAL);
commitTime = timeCommitted;
}
}
success = true;
return txId;
} catch (ConstraintValidationException | CreateConstraintFailureException e) {
throw new ConstraintViolationTransactionFailureException(e.getUserMessage(tokenRead()), e);
} finally {
if (!success) {
rollback(listenersState);
} else {
transactionId = txId;
afterCommit(listenersState);
}
transactionMonitor.addHeapTransactionSize(memoryTracker.heapHighWaterMark());
transactionMonitor.addNativeTransactionSize(memoryTracker.usedNativeMemory());
}
}
use of org.neo4j.internal.kernel.api.exceptions.TransactionFailureException in project neo4j by neo4j.
the class KernelTransactionImplementation method closeTransaction.
@Override
public long closeTransaction() throws TransactionFailureException {
assertTransactionOpen();
assertTransactionNotClosing();
closing = true;
try {
if (failure || !success || isTerminated()) {
rollback(null);
failOnNonExplicitRollbackIfNeeded();
return ROLLBACK_ID;
} else {
return commitTransaction();
}
} catch (TransactionFailureException e) {
throw e;
} catch (KernelException e) {
throw new TransactionFailureException(e.status(), e, "Unexpected kernel exception");
} finally {
try {
closed = true;
closing = false;
transactionEvent.setSuccess(success);
transactionEvent.setFailure(failure);
transactionEvent.setTransactionWriteState(writeState.name());
transactionEvent.setReadOnly(txState == null || !txState.hasChanges());
transactionEvent.close();
} finally {
release();
}
}
}
use of org.neo4j.internal.kernel.api.exceptions.TransactionFailureException 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.internal.kernel.api.exceptions.TransactionFailureException in project neo4j by neo4j.
the class TransactionStateMachine method commitTransaction.
@Override
public Bookmark commitTransaction() throws KernelException {
try {
BoltTransaction tx = ctx.currentTransaction;
state = state.commitTransaction(ctx, spi);
return newestBookmark(spi, tx);
} catch (TransactionFailureException ex) {
state = State.AUTO_COMMIT;
throw ex;
}
}
Aggregations