/** {@inheritDoc} */ public void join(TransactionParticipant participant) { assert Thread.currentThread() == owner : "Wrong thread"; if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "join {0} participant:{1}", this, participant); } if (participant == null) { throw new NullPointerException("Participant must not be null"); } else if (state == State.ABORTED) { throw new MaybeRetryableTransactionNotActiveException( "Transaction is not active", abortCause); } else if (state != State.ACTIVE) { throw new IllegalStateException("Transaction is not active: " + state); } if (!participants.contains(participant)) { if (participant instanceof NonDurableTransactionParticipant) { if (hasDurableParticipant) { participants.add(participants.size() - 1, participant); } else { participants.add(participant); } } else if (!hasDurableParticipant) { hasDurableParticipant = true; participants.add(participant); } else { throw new UnsupportedOperationException("Attempt to add multiple durable participants"); } } }
/** {@inheritDoc} */ public void abort(Throwable cause) { assert Thread.currentThread() == owner : "Wrong thread"; logger.log(Level.FINER, "abort {0}", this); switch (state) { case ACTIVE: case PREPARING: break; case ABORTING: return; case ABORTED: throw new MaybeRetryableTransactionNotActiveException( "Transaction is not active", abortCause); case COMMITTING: case COMMITTED: throw new IllegalStateException("Transaction is not active: " + state); default: throw new AssertionError(); } state = State.ABORTING; abortCause = cause; for (TransactionParticipant participant : participants) { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "abort {0} participant:{1}", this, participant); } try { participant.abort(this); } catch (RuntimeException e) { if (logger.isLoggable(Level.WARNING)) { logger.logThrow(Level.WARNING, e, "abort {0} participant:{1} failed", this, participant); } } } state = State.ABORTED; }
/** Creates an instance with the specified transaction ID. */ TransactionImpl(long tid) { this.tid = tid; creationTime = System.currentTimeMillis(); owner = Thread.currentThread(); state = State.ACTIVE; logger.log(Level.FINER, "create {0}", this); }
/** * Commits this transaction * * @throws TransactionNotActiveException if the transaction has been aborted * @throws TransactionAbortedException if a call to {@link TransactionParticipant#prepare prepare} * on a transaction participant aborts the transaction but does not throw an exception * @throws IllegalStateException if {@code prepare} has been called on any transaction participant * and {@link Transaction#abort abort} has not been called on the transaction * @throws Exception any exception thrown when calling {@code prepare} on a participant * @see TransactionHandle#commit TransactionHandle.commit */ void commit() throws Exception { assert Thread.currentThread() == owner : "Wrong thread"; logger.log(Level.FINER, "commit {0}", this); if (state == State.ABORTED) { throw new MaybeRetryableTransactionNotActiveException( "Transaction is not active", abortCause); } else if (state != State.ACTIVE) { throw new IllegalStateException("Transaction is not active: " + state); } state = State.PREPARING; for (Iterator<TransactionParticipant> iter = participants.iterator(); iter.hasNext(); ) { TransactionParticipant participant = iter.next(); try { if (iter.hasNext()) { boolean readOnly = participant.prepare(this); if (readOnly) { iter.remove(); } if (logger.isLoggable(Level.FINEST)) { logger.log( Level.FINEST, "prepare {0} participant:{1} returns {2}", this, participant, readOnly); } } else { participant.prepareAndCommit(this); iter.remove(); if (logger.isLoggable(Level.FINEST)) { logger.log( Level.FINEST, "prepareAndCommit {0} participant:{1} returns", this, participant); } } } catch (Exception e) { if (logger.isLoggable(Level.FINEST)) { logger.logThrow( Level.FINEST, e, "{0} {1} participant:{1} throws", iter.hasNext() ? "prepare" : "prepareAndCommit", this, participant); } if (state != State.ABORTED) { abort(e); } throw e; } if (state == State.ABORTED) { throw new MaybeRetryableTransactionAbortedException( "Transaction has been aborted", abortCause); } } state = State.COMMITTING; for (TransactionParticipant participant : participants) { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "commit {0} participant:{1}", this, participant); } try { participant.commit(this); } catch (RuntimeException e) { if (logger.isLoggable(Level.WARNING)) { logger.logThrow(Level.WARNING, e, "commit {0} participant:{1} failed", this, participant); } } } state = State.COMMITTED; }