in src/main/java/com/amazonaws/services/dynamodbv2/transactions/Transaction.java [431:500]
public synchronized void commit() throws TransactionRolledBackException, UnknownCompletedTransactionException {
// 1. Re-read transaction item
// a) If it doesn't exist, throw UnknownCompletedTransaction
// 2. Verify that we should continue
// a) If the transaction is closed, return or throw depending on COMPLETE or ROLLED_BACK.
// b) If the transaction is ROLLED_BACK, continue doRollback(), but at the end throw.
// c) If the transaction is COMMITTED, go to doCommit(), and at the end return.
// 3. Save the transaction's version number to detect if additional requests are added
// 4. Verify that we have all of the locks and their saved images
// 5. Change the state to COMMITTED conditioning on:
// - it isn't closed
// - the version number hasn't changed
// - it's still PENDING
// a) If that fails, go to 1).
// 6. Return success
for(int i = 0; i < ITEM_COMMIT_ATTEMPTS + 1; i++) {
// Re-read state to ensure this isn't a resume that's going to come along and re-apply a completed transaction.
// This doesn't prevent a transaction from being applied multiple times, but it prevents a sweeper from applying
// a very old transaction.
try {
txItem = new TransactionItem(txId, txManager, false);
} catch (TransactionNotFoundException tnfe) {
throw new UnknownCompletedTransactionException(txId, "In transaction " + State.COMMITTED + " attempt, transaction either rolled back or committed");
}
if(txItem.isCompleted()) {
if(State.COMMITTED.equals(txItem.getState())) {
return;
} else if(State.ROLLED_BACK.equals(txItem.getState())) {
throw new TransactionRolledBackException(txId, "Transaction was rolled back");
} else {
throw new TransactionAssertionException(txId, "Unexpected state for transaction: " + txItem.getState());
}
}
if(State.COMMITTED.equals(txItem.getState())) {
doCommit();
return;
}
if(State.ROLLED_BACK.equals(txItem.getState())) {
doRollback();
throw new TransactionRolledBackException(txId, "Transaction was rolled back");
}
// Commit attempts is actually for the number of times we try to acquire all the locks
if(! (i < ITEM_COMMIT_ATTEMPTS)) {
throw new TransactionException(txId, "Unable to commit transaction after " + ITEM_COMMIT_ATTEMPTS + " attempts");
}
int version = txItem.getVersion();
verifyLocks();
try {
txItem.finish(State.COMMITTED, version);
} catch (ConditionalCheckFailedException e) {
// Tx item version, changed out from under us, or was moved to committed, rolled back, deleted, etc by someone else.
// Retry in loop
}
}
throw new TransactionException(txId, "Unable to commit transaction after " + ITEM_COMMIT_ATTEMPTS + " attempts");
}