protected Map addRequest()

in src/main/java/com/amazonaws/services/dynamodbv2/transactions/Transaction.java [893:972]


    protected Map<String, AttributeValue> addRequest(Request callerRequest, boolean isRedrive, int numAttempts) throws DuplicateRequestException, 
        ItemNotLockedException, TransactionCompletedException, TransactionNotFoundException, TransactionException {
        
        // 1. Write the full caller request to the transaction item, but not if it's being re-driven.
        //    (In order to re-drive, the request must already be in the transaction item) 
        if(! isRedrive) {
            boolean success = false;
            for(int i = 0; i < numAttempts; i++) {
                // 1a. Verify the locks up to ensure that if we are adding a "read" request for an item that has been written to in this transaction,
                //     that we return the write.
                verifyLocks(); 
                try {
                    txItem.addRequest(callerRequest);
                    success = true;
                    break;
                } catch (ConditionalCheckFailedException e) {
                    // The transaction is either not in PENDING anymore, or the version number incremented from another thread/process
                    // registering a transaction (or we started cold on an existing transaction).
                    
                    txItem = new TransactionItem(txId, txManager, false);
                    
                    if(State.COMMITTED.equals(txItem.getState())) {
                        throw new TransactionCommittedException(txId, "Attempted to add a request to a transaction that was not in state " + State.PENDING + ", state is " + txItem.getState());
                    } else if(State.ROLLED_BACK.equals(txItem.getState())) {
                        throw new TransactionRolledBackException(txId, "Attempted to add a request to a transaction that was not in state " + State.PENDING + ", state is " + txItem.getState());
                    } else if(! State.PENDING.equals(txItem.getState())) {
                        throw new UnknownCompletedTransactionException(txId, "Attempted to add a request to a transaction that was not in state " + State.PENDING + ", state is " + txItem.getState());    
                    }
                }
            }
            
            if(! success) {
                throw new TransactionException(txId, "Unable to add request to transaction - too much contention for the tx record");
            }
        } else {
            txAssert(State.PENDING.equals(txItem.getState()), txId, "Attempted to add a request to a transaction that was not in state " + State.PENDING, "state", txItem.getState());
        }
        
        // 2. Write txId to item
        Map<String, AttributeValue> item = lockItem(callerRequest, true, ITEM_LOCK_ACQUIRE_ATTEMPTS);
        
        //    As long as this wasn't a duplicate read request,
        // 3. Save the item image to a new item in case we need to roll back, unless:
        //    - it's a lock request,
        //    - we've already saved the item image
        //    - the item is transient (inserted for acquiring the lock)
        saveItemImage(callerRequest, item);
        
        // 3a. Re-read the transaction item to make sure it hasn't been rolled back or completed.
        //     Can be optimized if we know the transaction is already completed(
        try {
            txItem = new TransactionItem(txId, txManager, false);
        } catch (TransactionNotFoundException e) {
            releaseReadLock(callerRequest.getTableName(), callerRequest.getKey(txManager));
            throw e;
        }
        switch (txItem.getState()) {
            case COMMITTED: 
                doCommit();
                throw new TransactionCommittedException(txId, "The transaction already committed");
            case ROLLED_BACK:
                doRollback();
                throw new TransactionRolledBackException(txId, "The transaction already rolled back");
            case PENDING:
                break;
            default:
                throw new TransactionException(txId, "Unexpected state " + txItem.getState());
        }
        
        // 4. Apply change to item, keeping lock on the item, returning the attributes according to RETURN_VALUE
        //    If we are a read request, and there is an applied delete request for the same item in the tx, return null.
        Map<String, AttributeValue> returnItem = applyAndKeepLock(callerRequest, item);
        
        // 5. Optimization: Keep track of the requests that this transaction object has fully applied
        if(callerRequest.getRid() != null) {
            fullyAppliedRequests.add(callerRequest.getRid());
        }
   
        return returnItem;
    }