com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException Java Examples

The following examples show how to use com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: MapperTransactionsIntegrationTest.java    From dynamodb-transactions with Apache License 2.0 6 votes vote down vote up
@Test
public void createVersionedItemWhenItemAlreadyExists() {
    ExampleVersionedHashKeyItem item1 = newVersionedItem();

    Transaction t1 = manager.newTransaction();
    t1.save(item1);
    t1.commit();
    assertItemNotLocked(INTEG_HASH_TABLE_NAME, item1.getKey(), item1.getExpectedValues(), true);

    ExampleVersionedHashKeyItem item2 = new ExampleVersionedHashKeyItem();
    item2.setId(item1.getId());
    Transaction t2 = manager.newTransaction();
    try {
        t2.save(item2);
        fail();
    } catch (ConditionalCheckFailedException e) {
        t2.rollback();
    }
    assertItemNotLocked(INTEG_HASH_TABLE_NAME, item1.getKey(), item1.getExpectedValues(), true);

    t1.delete(Long.MAX_VALUE);
    t2.delete(Long.MAX_VALUE);
}
 
Example #2
Source File: TransactionDynamoDBFacade.java    From dynamodb-transactions with Apache License 2.0 6 votes vote down vote up
/**
 * Checks a map of expected values against a map of actual values in a way
 * that's compatible with how the DynamoDB service interprets the Expected
 * parameter of PutItem, UpdateItem and DeleteItem.
 *
 * @param expectedValues
 *            A description of the expected values.
 * @param item
 *            The actual values.
 * @throws ConditionalCheckFailedException
 *             Thrown if the values do not match the expected values.
 */
public static void checkExpectedValues(Map<String, ExpectedAttributeValue> expectedValues, Map<String, AttributeValue> item) {
    for (Map.Entry<String, ExpectedAttributeValue> entry : expectedValues.entrySet()) {
        // if the attribute is expected to exist (null for isExists means
        // true)
        if ((entry.getValue().isExists() == null || entry.getValue().isExists() == true)
                // but the item doesn't
                && (item == null
                        // or the attribute doesn't
                        || item.get(entry.getKey()) == null
                        // or it doesn't have the expected value
                        || !expectedValueMatches(entry.getValue().getValue(), item.get(entry.getKey())))) {
            throw new ConditionalCheckFailedException(
                    "expected attribute(s) " + expectedValues
                            + " but found " + item);
        } else if (entry.getValue().isExists() != null
                && !entry.getValue().isExists()
                && item != null && item.get(entry.getKey()) != null) {
            // the attribute isn't expected to exist, but the item exists
            // and the attribute does too
            throw new ConditionalCheckFailedException(
                    "expected attribute(s) " + expectedValues
                            + " but found " + item);
        }
    }
}
 
Example #3
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 6 votes vote down vote up
/**
 * Inserts a new transaction item into the table.  Assumes txKey is already initialized.
 * @return the txItem
 * @throws TransactionException if the transaction already exists
 */
private Map<String, AttributeValue> insert() {
    Map<String, AttributeValue> item = new HashMap<String, AttributeValue>();
    item.put(AttributeName.STATE.toString(), new AttributeValue(STATE_PENDING));
    item.put(AttributeName.VERSION.toString(), new AttributeValue().withN(Integer.toString(1)));
    item.put(AttributeName.DATE.toString(), txManager.getCurrentTimeAttribute());
    item.putAll(txKey);
    
    Map<String, ExpectedAttributeValue> expectNotExists = new HashMap<String, ExpectedAttributeValue>(2);
    expectNotExists.put(AttributeName.TXID.toString(), new ExpectedAttributeValue(false));
    expectNotExists.put(AttributeName.STATE.toString(), new ExpectedAttributeValue(false));
    
    PutItemRequest request = new PutItemRequest()
        .withTableName(txManager.getTransactionTableName())
        .withItem(item)
        .withExpected(expectNotExists);
    
    try {
        txManager.getClient().putItem(request);
        return item;
    } catch (ConditionalCheckFailedException e) {
        throw new TransactionException("Failed to create new transaction with id " + txId, e);
    }
}
 
Example #4
Source File: Transaction.java    From dynamodb-transactions with Apache License 2.0 6 votes vote down vote up
/**
 * Deletes the transaction item from the database.
 * 
 * Does not throw if the item is gone, even if the conditional check to delete the item fails, and this method doesn't know what state
 * it was in when deleted.  The caller is responsible for guaranteeing that it was actually in "currentState" immediately before calling
 * this method.  
 */
protected void complete(final State expectedCurrentState) {
    try {
        txItem.complete(expectedCurrentState);
    } catch (ConditionalCheckFailedException e) {
        // Re-read state to ensure it was already completed
        try {
            txItem = new TransactionItem(txId, txManager, false);
            if(! txItem.isCompleted()) {
                throw new TransactionAssertionException(txId, "Expected the transaction to be completed (no item), but there was one.");
            }
        } catch (TransactionNotFoundException tnfe) {
            // expected - transaction record no longer exists
        }
    }
}
 
Example #5
Source File: GenericDynamoDB.java    From strongbox with Apache License 2.0 6 votes vote down vote up
@Override
public void create(Entry entry) {
    readWriteLock.writeLock().lock();

    try {
        Map<String, AttributeValue> keys = createKey(entry);
        Map<String, AttributeValueUpdate> attributes = createAttributes(entry);
        Map<String, ExpectedAttributeValue> expected = expectNotExists();

        try {
            executeUpdate(keys, attributes, expected);
        } catch (ConditionalCheckFailedException e) {
            throw new AlreadyExistsException("DynamoDB store entry already exists:" + keys.toString());
        }
    } finally {
        readWriteLock.writeLock().unlock();
    }
}
 
Example #6
Source File: GenericDynamoDB.java    From strongbox with Apache License 2.0 6 votes vote down vote up
@Override
public void update(Entry entry, Entry existingEntry) {
    readWriteLock.writeLock().lock();

    try {
        Map<String, AttributeValue> keys = createKey(entry);
        Map<String, AttributeValueUpdate> attributes = createAttributes(entry);
        Map<String, ExpectedAttributeValue> expected = expectExists(existingEntry);

        try {
            executeUpdate(keys, attributes, expected);
        } catch (ConditionalCheckFailedException e) {
            throw new DoesNotExistException("Precondition to update entry in DynamoDB failed:" + keys.toString());
        }
    } finally {
        readWriteLock.writeLock().unlock();
    }

}
 
Example #7
Source File: GenericDynamoDBTest.java    From strongbox with Apache License 2.0 6 votes vote down vote up
@Test
public void testUpdateEntryDoesNotExist() throws Exception {
    RawSecretEntry rawSecretEntry = constructRawEntry(SECRET_NAME);
    RawSecretEntry alternativeRawSecretEntry = constructAlternativeRawSecretEntry(SECRET_NAME);

    UpdateItemRequest expectedUpdateRequest = constructUpdateItemRequest(rawSecretEntry, true, Optional.of(alternativeRawSecretEntry));

    when(mockDynamoDBClient.updateItem(expectedUpdateRequest)).thenThrow(
            new ConditionalCheckFailedException(""));

    boolean exceptionThrown = false;
    try {
        dynamoDB.update(rawSecretEntry, alternativeRawSecretEntry);
    } catch (DoesNotExistException e) {
        assertEquals(e.getMessage(), "Precondition to update entry in DynamoDB failed:{1={S: secret1,}, 2={N: 1,}}");
        exceptionThrown = true;
    }
    assertTrue(exceptionThrown);

    // Check all the expected calls to AWS were made.
    verify(mockDynamoDBClient, times(1)).updateItem(expectedUpdateRequest);
}
 
Example #8
Source File: MapperTransactionsIntegrationTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void reusingMapperInstanceWithOutOfDateVersionThrowsOnSave() {
    ExampleVersionedHashKeyItem item1 = newVersionedItem();

    // establish the item with version 1
    Transaction t1 = manager.newTransaction();
    t1.save(item1);
    t1.commit();

    // update the item to version 2 and save
    Transaction t2 = manager.newTransaction();
    ExampleVersionedHashKeyItem item2 = t2.load(item1);
    t2.save(item2);
    t2.commit();

    Transaction t3 = manager.newTransaction();
    t3.load(item1);
    try {
        t3.save(item1);
        fail();
    } catch (ConditionalCheckFailedException e) {
        t3.rollback();
    }
    assertItemNotLocked(INTEG_HASH_TABLE_NAME, item2.getKey(), item2.getExpectedValues(), true);

    t1.delete(Long.MAX_VALUE);
    t2.delete(Long.MAX_VALUE);
    t3.delete(Long.MAX_VALUE);
}
 
Example #9
Source File: TransactionDynamoDBFacade.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
private void checkExpectedValues(String tableName,
        Map<String, AttributeValue> itemKey,
        Map<String, ExpectedAttributeValue> expectedValues) {
    if (expectedValues != null && !expectedValues.isEmpty()) {
        for (Map.Entry<String, ExpectedAttributeValue> entry : expectedValues.entrySet()) {
            if ((entry.getValue().isExists() == null || entry.getValue().isExists() == true)
                    && entry.getValue().getValue() == null) {
                throw new IllegalArgumentException("An explicit value is required when Exists is null or true, "
                        + "but none was found in expected values for item with key " + itemKey +
                        ": " + expectedValues);
            }
        }

        // simulate by loading the item and checking the values;
        // this also has the effect of locking the item, which gives the
        // same behavior
        GetItemResult result = getItem(new GetItemRequest()
                .withAttributesToGet(expectedValues.keySet())
                .withKey(itemKey)
                .withTableName(tableName));
        Map<String, AttributeValue> item = result.getItem();
        try {
            checkExpectedValues(expectedValues, item);
        } catch (ConditionalCheckFailedException e) {
            throw new ConditionalCheckFailedException("Item " + itemKey + " had unexpected attributes: " + e.getMessage());
        }
    }
}
 
Example #10
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Deletes the tx item, only if it was in the "finalized" state.
 * 
 * @throws ConditionalCheckFailedException if the item does not exist or is not finalized
 */
public void delete() throws ConditionalCheckFailedException {
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(1);
    expected.put(AttributeName.FINALIZED.toString(), new ExpectedAttributeValue().withValue(new AttributeValue(Transaction.BOOLEAN_TRUE_ATTR_VAL)));
    
    DeleteItemRequest completeRequest = new DeleteItemRequest()
        .withTableName(txManager.getTransactionTableName())
        .withKey(txKey)
        .withExpected(expected);
    txManager.getClient().deleteItem(completeRequest);
}
 
Example #11
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Completes a transaction by marking its "Finalized" attribute.  This leaves the completed transaction item around
 * so that the party who created the transaction can see whether it was completed or rolled back.  They can then either 
 * delete the transaction record when they're done, or they can run a sweeper process to go and delete the completed transactions
 * later on. 
 * 
 * @param expectedCurrentState
 * @throws ConditionalCheckFailedException if the transaction is completed, doesn't exist anymore, or even if it isn't committed or rolled back  
 */
public void complete(final State expectedCurrentState) throws ConditionalCheckFailedException {
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(2);
    
    if(State.COMMITTED.equals(expectedCurrentState)) {
        expected.put(AttributeName.STATE.toString(), new ExpectedAttributeValue(new AttributeValue(STATE_COMMITTED)));
    } else if(State.ROLLED_BACK.equals(expectedCurrentState)) {
        expected.put(AttributeName.STATE.toString(), new ExpectedAttributeValue(new AttributeValue(STATE_ROLLED_BACK)));
    } else {
        throw new TransactionAssertionException(txId, "Illegal state in finish(): " + expectedCurrentState + " txItem " + txItem);
    }
    
    Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();
    updates.put(AttributeName.FINALIZED.toString(), new AttributeValueUpdate()
        .withAction(AttributeAction.PUT)
        .withValue(new AttributeValue(Transaction.BOOLEAN_TRUE_ATTR_VAL)));
    updates.put(AttributeName.DATE.toString(), new AttributeValueUpdate()
        .withAction(AttributeAction.PUT)
        .withValue(txManager.getCurrentTimeAttribute()));
    
    UpdateItemRequest completeRequest = new UpdateItemRequest()
        .withTableName(txManager.getTransactionTableName())
        .withKey(txKey)
        .withAttributeUpdates(updates)
        .withReturnValues(ReturnValue.ALL_NEW)
        .withExpected(expected);
    
    txItem = txManager.getClient().updateItem(completeRequest).getAttributes();
}
 
Example #12
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Marks the transaction item as either COMMITTED or ROLLED_BACK, but only if it was in the PENDING state.
 * It will also condition on the expected version. 
 * 
 * @param targetState
 * @param expectedVersion 
 * @throws ConditionalCheckFailedException if the transaction doesn't exist, isn't PENDING, is finalized, 
 *         or the expected version doesn't match (if specified)  
 */
public void finish(final State targetState, final int expectedVersion) throws ConditionalCheckFailedException {
    txAssert(State.COMMITTED.equals(targetState) || State.ROLLED_BACK.equals(targetState),"Illegal state in finish(): " + targetState, "txItem", txItem);
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(2);
    expected.put(AttributeName.STATE.toString(), new ExpectedAttributeValue().withValue(new AttributeValue().withS(STATE_PENDING)));
    expected.put(AttributeName.FINALIZED.toString(), new ExpectedAttributeValue().withExists(false));
    expected.put(AttributeName.VERSION.toString(), new ExpectedAttributeValue().withValue(new AttributeValue().withN(Integer.toString(expectedVersion))));
    
    Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();
    updates.put(AttributeName.STATE.toString(), new AttributeValueUpdate()
        .withAction(AttributeAction.PUT)
        .withValue(new AttributeValue(stateToString(targetState))));
    updates.put(AttributeName.DATE.toString(), new AttributeValueUpdate()
        .withAction(AttributeAction.PUT)
        .withValue(txManager.getCurrentTimeAttribute()));
    
    UpdateItemRequest finishRequest = new UpdateItemRequest()
        .withTableName(txManager.getTransactionTableName())
        .withKey(txKey)
        .withAttributeUpdates(updates)
        .withReturnValues(ReturnValue.ALL_NEW)
        .withExpected(expected);
    
    UpdateItemResult finishResult = txManager.getClient().updateItem(finishRequest);
    txItem = finishResult.getAttributes();
    if(txItem == null) {
        throw new TransactionAssertionException(txId, "Unexpected null tx item after committing " + targetState);
    }
}
 
Example #13
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Saves the old copy of the item.  Does not mutate the item, unless an exception is thrown.
 * 
 * @param item
 * @param rid
 */
public void saveItemImage(Map<String, AttributeValue> item, int rid) {
    txAssert(! item.containsKey(AttributeName.APPLIED.toString()), txId, "The transaction has already applied this item image, it should not be saving over the item image with it");
    
    AttributeValue existingTxId = item.put(AttributeName.TXID.toString(), new AttributeValue(txId));
    if(existingTxId != null && ! txId.equals(existingTxId.getS())) {
        throw new TransactionException(txId, "Items in transactions may not contain the attribute named " + AttributeName.TXID.toString());
    }
    
    // Don't save over the already saved item.  Prevents us from saving the applied image instead of the previous image in the case
    // of a re-drive.
    // If we want to be extremely paranoid, we could expect every attribute to be set exactly already in a second write step, and assert
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(1);
    expected.put(AttributeName.IMAGE_ID.toString(), new ExpectedAttributeValue().withExists(false));
    
    AttributeValue existingImageId = item.put(AttributeName.IMAGE_ID.toString(), new AttributeValue(txId + "#" + rid));
    if(existingImageId != null) {
        throw new TransactionException(txId, "Items in transactions may not contain the attribute named " + AttributeName.IMAGE_ID.toString() + ", value was already " + existingImageId); 
    }
    
    // TODO failures?  Size validation?
    try {
        txManager.getClient().putItem(new PutItemRequest()
            .withTableName(txManager.getItemImageTableName())
            .withExpected(expected)
            .withItem(item));
    } catch (ConditionalCheckFailedException e) {
        // Already was saved
    }
    
    // do not mutate the item for the customer unless if there aren't exceptions
    item.remove(AttributeName.IMAGE_ID.toString());
}
 
Example #14
Source File: GenericDynamoDBTest.java    From strongbox with Apache License 2.0 5 votes vote down vote up
@Test
public void testCreateEntryAlreadyExists() throws Exception {
    RawSecretEntry rawSecretEntry = constructRawEntry(SECRET_NAME);
    UpdateItemRequest expectedUpdateRequest = constructUpdateItemRequest(rawSecretEntry, false, Optional.empty());

    // Already exists will cause a check failed exception.
    when(mockDynamoDBClient.updateItem(expectedUpdateRequest)).thenThrow(
            new ConditionalCheckFailedException(""));

    boolean exceptionThrown = false;
    try {
        dynamoDB.create(rawSecretEntry);
    } catch (AlreadyExistsException e) {
        assertEquals(e.getMessage(), "DynamoDB store entry already exists:{1={S: secret1,}, 2={N: 1,}}");
        exceptionThrown = true;
    }
    assertTrue(exceptionThrown);
    verify(mockDynamoDBClient, times(1)).updateItem(expectedUpdateRequest);
}
 
Example #15
Source File: Transaction.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
protected static void releaseReadLock(String txId, TransactionManager txManager, String tableName, Map<String, AttributeValue> key) {
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>();
    expected.put(AttributeName.TXID.toString(), new ExpectedAttributeValue().withValue(new AttributeValue(txId)));
    expected.put(AttributeName.TRANSIENT.toString(), new ExpectedAttributeValue().withExists(false));
    expected.put(AttributeName.APPLIED.toString(), new ExpectedAttributeValue().withExists(false));
    
    try {
        Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>(1);
        updates.put(AttributeName.TXID.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
        updates.put(AttributeName.DATE.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
        
        UpdateItemRequest update = new UpdateItemRequest()
            .withTableName(tableName)
            .withAttributeUpdates(updates)
            .withKey(key)
            .withExpected(expected);
        txManager.getClient().updateItem(update);
    } catch (ConditionalCheckFailedException e) {
        try {
            expected.put(AttributeName.TRANSIENT.toString(), new ExpectedAttributeValue().withValue(new AttributeValue().withS(BOOLEAN_TRUE_ATTR_VAL)));
            
            DeleteItemRequest delete = new DeleteItemRequest()
                .withTableName(tableName)
                .withKey(key)
                .withExpected(expected);
            txManager.getClient().deleteItem(delete);    
        } catch (ConditionalCheckFailedException e1) {
            // Ignore, means it was definitely rolled back
            // Re-read to ensure that it wasn't applied
            Map<String, AttributeValue> item = getItem(txManager, tableName, key);
            txAssert(! (item != null && txId.equals(getOwner(item)) && item.containsKey(AttributeName.APPLIED.toString())), 
                "Item should not have been applied.  Unable to release lock", "item", item);
        }
    }
}
 
Example #16
Source File: Transaction.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Releases the lock for the item.  If the item was inserted only to acquire the lock (if the item didn't exist before 
 * for a DeleteItem or LockItem), it will be deleted now.
 * 
 * Otherwise, all of the attributes uses for the transaction (tx id, transient flag, applied flag) will be removed.
 * 
 * Conditions on our transaction id owning the item
 * 
 * To be used once the transaction has committed only.
 * @param request
 */
protected void unlockItemAfterCommit(Request request) {
    try {
        Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>();
        expected.put(AttributeName.TXID.toString(), new ExpectedAttributeValue().withValue(new AttributeValue(txId)));
        
        if(request instanceof PutItem || request instanceof UpdateItem) {
            Map<String, AttributeValueUpdate> updates = new HashMap<String, AttributeValueUpdate>();
            updates.put(AttributeName.TXID.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
            updates.put(AttributeName.TRANSIENT.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
            updates.put(AttributeName.APPLIED.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
            updates.put(AttributeName.DATE.toString(), new AttributeValueUpdate().withAction(AttributeAction.DELETE));
            
            UpdateItemRequest update = new UpdateItemRequest()
                .withTableName(request.getTableName())
                .withKey(request.getKey(txManager))
                .withAttributeUpdates(updates)
                .withExpected(expected);
            txManager.getClient().updateItem(update);
        } else if(request instanceof DeleteItem) {
            DeleteItemRequest delete = new DeleteItemRequest()
                .withTableName(request.getTableName())
                .withKey(request.getKey(txManager))
                .withExpected(expected);
            txManager.getClient().deleteItem(delete);
        } else if(request instanceof GetItem) {
            releaseReadLock(request.getTableName(), request.getKey(txManager));
        } else {
            throw new TransactionAssertionException(txId, "Unknown request type: " + request.getClass());
        }
    } catch (ConditionalCheckFailedException e) {
        // ignore, unlock already happened
        // TODO if we really want to be paranoid we could condition on applied = 1, and then here
        //      we would have to read the item again and make sure that applied was 1 if we owned the lock (and assert otherwise) 
    }
}
 
Example #17
Source File: Transaction.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Rolls back the transaction.  You can only roll back a transaction that is in the PENDING state (not yet committed).
 * <li>If you roll back a transaction in COMMITTED, this will continue committing the transaction if it isn't completed yet, 
 *      but you will get back a TransactionCommittedException. </li>
 * <li>If you roll back and already rolled back transaction, this will ensure the rollback completed, and return success</li>
 * <li>If the transaction no longer exists, you'll get back an UnknownCompletedTransactionException</li>   
 * 
 * @throws TransactionCommittedException - the transaction was committed by a concurrent overlapping transaction
 * @throws UnknownCompletedTransactionException - the transaction completed, but it is not known whether it was rolled back or committed
 */
public synchronized void rollback() throws TransactionCompletedException, UnknownCompletedTransactionException {
    State state = null;
    boolean alreadyRereadTxItem = false;
    try {
        txItem.finish(State.ROLLED_BACK, txItem.getVersion());  
        state = State.ROLLED_BACK;
    } catch (ConditionalCheckFailedException e) {         
        try {
            // Re-read state to see its actual state, since it wasn't in PENDING
            txItem = new TransactionItem(txId, txManager, false);
            alreadyRereadTxItem = true;
            state = txItem.getState();
        } catch (TransactionNotFoundException tnfe) {
            throw new UnknownCompletedTransactionException(txId, "In transaction " + State.ROLLED_BACK + " attempt, transaction either rolled back or committed");
        }
    }
    
    if(State.COMMITTED.equals(state)) {
        if(! txItem.isCompleted()) {
            doCommit();
        }
        throw new TransactionCommittedException(txId, "Transaction was committed");
    } else if(State.ROLLED_BACK.equals(state)) {
        if(! txItem.isCompleted()) {
            doRollback();
        }
        return;
    } else if (State.PENDING.equals(state)) {
        if (! alreadyRereadTxItem) {
            // The item was modified in the meantime (another request was added to it)
            // so make sure we re-read it, and then try the rollback again
            txItem = new TransactionItem(txId, txManager, false);
        }
        rollback();
        return;
    }
    throw new TransactionAssertionException(txId, "Unexpected state in rollback(): " + state);
}
 
Example #18
Source File: DynamoDBLockProvider.java    From ShedLock with Apache License 2.0 5 votes vote down vote up
@Override
@NonNull
public Optional<SimpleLock> lock(@NonNull LockConfiguration lockConfiguration) {
    String nowIso = toIsoString(now());
    String lockUntilIso = toIsoString(lockConfiguration.getLockAtMostUntil());

    UpdateItemSpec request = new UpdateItemSpec()
            .withPrimaryKey(ID, lockConfiguration.getName())
            .withUpdateExpression(OBTAIN_LOCK_QUERY)
            .withConditionExpression(OBTAIN_LOCK_CONDITION)
            .withValueMap(new ValueMap()
                    .withString(":lockUntil", lockUntilIso)
                    .withString(":lockedAt", nowIso)
                    .withString(":lockedBy", hostname)
            )
            .withReturnValues(ReturnValue.UPDATED_NEW);

    try {
        // There are three possible situations:
        // 1. The lock document does not exist yet - it is inserted - we have the lock
        // 2. The lock document exists and lockUtil <= now - it is updated - we have the lock
        // 3. The lock document exists and lockUtil > now - ConditionalCheckFailedException is thrown
        table.updateItem(request);
        return Optional.of(new DynamoDBLock(table, lockConfiguration));
    } catch (ConditionalCheckFailedException e) {
        // Condition failed. This means there was a lock with lockUntil > now.
        return Optional.empty();
    }
}
 
Example #19
Source File: MapperTransactionsIntegrationTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void deleteVersionedItemWithOutOfDateVersion() {
    ExampleVersionedHashKeyItem item1 = newVersionedItem();

    // establish the item with version 1
    Transaction t1 = manager.newTransaction();
    t1.save(item1);
    t1.commit();

    // update the item to version 2
    Transaction t2 = manager.newTransaction();
    ExampleVersionedHashKeyItem item2 = t2.load(item1);
    t2.save(item2);
    t2.commit();

    // try to delete with an outdated view of the item
    Transaction t3 = manager.newTransaction();
    try {
        t3.delete(item1);
        fail();
    } catch (ConditionalCheckFailedException e) {
        t3.rollback();
    }
    assertItemNotLocked(INTEG_HASH_TABLE_NAME, item2.getKey(), item2.getExpectedValues(), true);

    t1.delete(Long.MAX_VALUE);
    t2.delete(Long.MAX_VALUE);
    t3.delete(Long.MAX_VALUE);
}
 
Example #20
Source File: LowLevelItemCRUDExample.java    From aws-doc-sdk-examples with Apache License 2.0 5 votes vote down vote up
private static void updateExistingAttributeConditionally() {
    try {

        HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue>();
        key.put("Id", new AttributeValue().withN("120"));

        // Specify the desired price (25.00) and also the condition (price =
        // 20.00)

        Map<String, AttributeValue> expressionAttributeValues = new HashMap<String, AttributeValue>();
        expressionAttributeValues.put(":val1", new AttributeValue().withN("25.00"));
        expressionAttributeValues.put(":val2", new AttributeValue().withN("20.00"));

        ReturnValue returnValues = ReturnValue.ALL_NEW;

        UpdateItemRequest updateItemRequest = new UpdateItemRequest().withTableName(tableName).withKey(key)
            .withUpdateExpression("set Price = :val1").withConditionExpression("Price = :val2")
            .withExpressionAttributeValues(expressionAttributeValues).withReturnValues(returnValues);

        UpdateItemResult result = client.updateItem(updateItemRequest);

        // Check the response.
        System.out.println("Printing item after conditional update to new attribute...");
        printItem(result.getAttributes());
    }
    catch (ConditionalCheckFailedException cse) {
        // Reload object and retry code.
        System.err.println("Conditional check failed in " + tableName);
    }
    catch (AmazonServiceException ase) {
        System.err.println("Error updating item in " + tableName);
    }
}
 
Example #21
Source File: MoviesItemOps05.java    From aws-dynamodb-examples with Apache License 2.0 5 votes vote down vote up
public static void main(String[] args)  {

        AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        client.setEndpoint("http://localhost:8000");
        DynamoDB dynamoDB = new DynamoDB(client);

        Table table = dynamoDB.getTable("Movies");
        
        int year = 2015;
        String title = "The Big New Movie";

        // Conditional update (will fail)

        UpdateItemSpec updateItemSpec = new UpdateItemSpec()
            .withPrimaryKey(new PrimaryKey("year", 2015, "title",  "The Big New Movie"))
            .withUpdateExpression("remove info.actors[0]")
            .withConditionExpression("size(info.actors) > :num")
            .withValueMap(new ValueMap().withNumber(":num", 3));

        System.out.println("Attempting a conditional update...");
        try {
            table.updateItem(updateItemSpec);
            System.out.println("UpdateItem succeeded: " + table.getItem("year", year, "title", title).toJSONPretty());
        } catch (ConditionalCheckFailedException e) {
            e.printStackTrace();
            System.out.println("UpdateItem failed");
        }

    }
 
Example #22
Source File: MoviesItemOps02.java    From aws-dynamodb-examples with Apache License 2.0 5 votes vote down vote up
public static void main(String[] args)  {

        AmazonDynamoDBClient client = new AmazonDynamoDBClient();
        client.setEndpoint("http://localhost:8000");
        DynamoDB dynamoDB = new DynamoDB(client);

        Table table = dynamoDB.getTable("Movies");

        int year = 2015;
        String title = "The Big New Movie";

        final Map<String, Object> infoMap = new HashMap<String, Object>();
        infoMap.put("plot",  "Nothing happens at all.");
        infoMap.put("rating",  0.0);
        Item item = new Item()
            .withPrimaryKey(new PrimaryKey("year", year, "title", title))
            .withMap("info", infoMap);
        
        // Attempt a conditional write.  We expect this to fail.

        PutItemSpec putItemSpec = new PutItemSpec()
            .withItem(item)
            .withConditionExpression("attribute_not_exists(#yr) and attribute_not_exists(title)")
            .withNameMap(new NameMap()
                .with("#yr", "year"));
        
        System.out.println("Attempting a conditional write...");
        try {
            table.putItem(putItemSpec);
            System.out.println("PutItem succeeded: " + table.getItem("year", year, "title", title).toJSONPretty());
        } catch (ConditionalCheckFailedException e) {
            e.printStackTrace(System.err);
            System.out.println("PutItem failed");
        }
    }
 
Example #23
Source File: LowLevelItemCRUDExample.java    From aws-dynamodb-examples with Apache License 2.0 5 votes vote down vote up
private static void updateExistingAttributeConditionally() {
    try {
        

        HashMap<String, AttributeValue> key = new HashMap<String, AttributeValue>();
        key.put("Id", new AttributeValue().withN("120"));

        // Specify the desired price (25.00) and also the condition (price = 20.00)
       
        Map<String, AttributeValue> expressionAttributeValues = new HashMap<String, AttributeValue>();
        expressionAttributeValues.put(":val1", new AttributeValue().withN("25.00")); 
        expressionAttributeValues.put(":val2", new AttributeValue().withN("20.00")); 
        
        ReturnValue returnValues = ReturnValue.ALL_NEW;

        UpdateItemRequest updateItemRequest = new UpdateItemRequest()
            .withTableName(tableName)
            .withKey(key)
            .withUpdateExpression("set Price = :val1")
            .withConditionExpression("Price = :val2")
            .withExpressionAttributeValues(expressionAttributeValues)
            .withReturnValues(returnValues);

        UpdateItemResult result = client.updateItem(updateItemRequest);
        
        // Check the response.
        System.out.println("Printing item after conditional update to new attribute...");
        printItem(result.getAttributes());            
    } catch (ConditionalCheckFailedException cse) {
        // Reload object and retry code.
        System.err.println("Conditional check failed in " + tableName);
    } catch (AmazonServiceException ase) {
        System.err.println("Error updating item in " + tableName);
    }        
}
 
Example #24
Source File: SavePersonHandler.java    From tutorials with MIT License 5 votes vote down vote up
private PutItemOutcome persistData(PersonRequest personRequest) throws ConditionalCheckFailedException {
    return this.dynamoDb.getTable(DYNAMODB_TABLE_NAME)
      .putItem(
        new PutItemSpec().withItem(new Item()
          .withNumber("id", personRequest.getId())
          .withString("firstName", personRequest.getFirstName())
          .withString("lastName", personRequest.getLastName())
          .withNumber("age", personRequest.getAge())
          .withString("address", personRequest.getAddress())));
}
 
Example #25
Source File: DynamoDocumentStoreTemplateTest.java    From Cheddar with Apache License 2.0 5 votes vote down vote up
@Test
public void shouldNotUpdate_withPutItemException() {
    // Given
    final ItemId itemId = new ItemId(randomId());
    final StubItem stubItem = generateRandomStubItem(itemId);
    final StubItem previousStubItem = generateRandomStubItem(itemId);
    final ItemConfiguration itemConfiguration = new ItemConfiguration(StubItem.class, tableName);
    final Collection<ItemConfiguration> itemConfigurations = Arrays.asList(itemConfiguration);
    final Table mockTable = mock(Table.class);
    final Item mockTableItem = mock(Item.class);
    final PrimaryKey primaryKey = new PrimaryKey();
    primaryKey.addComponent("id", itemId.value());
    final Item previousItem = mock(Item.class);

    when(mockDatabaseSchemaHolder.itemConfigurations()).thenReturn(itemConfigurations);
    when(mockDynamoDBClient.getTable(schemaName + "." + tableName)).thenReturn(mockTable);
    when(mockTable.getItem(any(PrimaryKey.class))).thenReturn(previousItem);

    final DynamoDocumentStoreTemplate dynamoDocumentStoreTemplate = new DynamoDocumentStoreTemplate(
            mockDatabaseSchemaHolder);
    when(previousItem.toJSON()).thenReturn(dynamoDocumentStoreTemplate.itemToString(previousStubItem));
    when(mockTableItem.toJSON()).thenReturn(dynamoDocumentStoreTemplate.itemToString(stubItem));
    when(mockTable.putItem(any(PutItemSpec.class))).thenThrow(ConditionalCheckFailedException.class);

    dynamoDocumentStoreTemplate.initialize(mockAmazonDynamoDbClient);

    // When
    OptimisticLockException thrownException = null;
    try {
        dynamoDocumentStoreTemplate.update(stubItem);
    } catch (final OptimisticLockException optimisticLockException) {
        thrownException = optimisticLockException;
    }

    // Then
    assertNotNull(thrownException);
}
 
Example #26
Source File: DynamoDocumentStoreTemplate.java    From Cheddar with Apache License 2.0 5 votes vote down vote up
@Override
public <T extends Item> T update(final T item,
        final PersistenceExceptionHandler<?>... persistenceExceptionHandlers) {
    final ItemConfiguration itemConfiguration = getItemConfiguration(item.getClass());
    if (item.getVersion() == null) {
        return create(item);
    }

    final Expected expectedCondition = new Expected(VERSION_ATTRIBUTE).eq(item.getVersion());
    final Long newVersion = item.getVersion() + 1l;
    item.setVersion(newVersion);

    final String tableName = databaseSchemaHolder.schemaName() + "." + itemConfiguration.tableName();
    final String itemJson = itemToString(item);
    final PrimaryKey primaryKey = new PrimaryKey();
    final ItemId itemId = itemConfiguration.getItemId(item);
    final PrimaryKeyDefinition primaryKeyDefinition = itemConfiguration.primaryKeyDefinition();
    primaryKey.addComponent(primaryKeyDefinition.propertyName(), itemId.value());
    if (primaryKeyDefinition instanceof CompoundPrimaryKeyDefinition) {
        primaryKey.addComponent(((CompoundPrimaryKeyDefinition) primaryKeyDefinition).supportingPropertyName(),
                itemId.supportingValue());
    }
    final Table table = dynamoDBClient.getTable(tableName);
    final com.amazonaws.services.dynamodbv2.document.Item previousAwsItem = table.getItem(primaryKey);
    final String previousItemJson = previousAwsItem.toJSON();

    final String mergedJson = mergeJSONObjects(itemJson, previousItemJson);
    final com.amazonaws.services.dynamodbv2.document.Item awsItem = com.amazonaws.services.dynamodbv2.document.Item
            .fromJSON(mergedJson);
    final PutItemSpec putItemSpec = new PutItemSpec().withItem(awsItem).withExpected(expectedCondition);
    try {
        table.putItem(putItemSpec);
    } catch (final ConditionalCheckFailedException e) {
        throw new OptimisticLockException("Conflicting write detected while updating item");
    }
    return item;
}
 
Example #27
Source File: MetaStore.java    From aws-dynamodb-encryption-java with Apache License 2.0 5 votes vote down vote up
private Map<String, AttributeValue> conditionalPut(final Map<String, AttributeValue> item) {
    try {
        final PutItemRequest put = new PutItemRequest().withTableName(tableName).withItem(item)
                .withExpected(doesNotExist);
        ddb.putItem(put);
        return item;
    } catch (final ConditionalCheckFailedException ex) {
        final Map<String, AttributeValue> ddbKey = new HashMap<>();
        ddbKey.put(DEFAULT_HASH_KEY, item.get(DEFAULT_HASH_KEY));
        ddbKey.put(DEFAULT_RANGE_KEY, item.get(DEFAULT_RANGE_KEY));
        return ddbGet(ddbKey);
    }
}
 
Example #28
Source File: MetaStore.java    From aws-dynamodb-encryption-java with Apache License 2.0 5 votes vote down vote up
/**
 * This API retrieves the intermediate keys from the source region and replicates it in the target region.
 *
 * @param materialName material name of the encryption material.
 * @param version version of the encryption material.
 * @param targetMetaStore target MetaStore where the encryption material to be stored.
 */
public void replicate(final String materialName, final long version, final MetaStore targetMetaStore) {
    try {
        Map<String, AttributeValue> item = getMaterialItem(materialName, version);
        final Map<String, AttributeValue> plainText = getPlainText(item);
        final Map<String, AttributeValue> encryptedText = targetMetaStore.getEncryptedText(plainText);
        final PutItemRequest put = new PutItemRequest().withTableName(targetMetaStore.tableName).withItem(encryptedText)
                .withExpected(doesNotExist);
        targetMetaStore.ddb.putItem(put);
    } catch (ConditionalCheckFailedException e) {
        //Item already present.
    }
}
 
Example #29
Source File: DynamoDbDelegate.java    From dynamodb-janusgraph-storage-backend with Apache License 2.0 5 votes vote down vote up
private BackendException processDynamoDbApiException(final Throwable e, final String apiName, final String tableName) {
    Preconditions.checkArgument(apiName != null);
    Preconditions.checkArgument(!apiName.isEmpty());
    final String prefix;
    if (tableName == null) {
        prefix = apiName;
    } else {
        prefix = String.format("%s_%s", apiName, tableName);
    }
    final String message = String.format("%s %s", prefix, e.getMessage());
    if (e instanceof ResourceNotFoundException) {
        return new BackendNotFoundException(String.format("%s; table not found", message), e);
    } else if (e instanceof ConditionalCheckFailedException) {
        return new PermanentLockingException(message, e);
    } else if (e instanceof AmazonServiceException) {
        if (e.getMessage() != null
            && (e.getMessage().contains(HASH_RANGE_KEY_SIZE_LIMIT) || e.getMessage().contains(UPDATE_ITEM_SIZE_LIMIT))) {
            return new PermanentBackendException(message, e);
        } else {
            return new TemporaryBackendException(message, e);
        }
    } else if (e instanceof AmazonClientException) { //all client exceptions are retriable by default
        return new TemporaryBackendException(message, e);
    } else if (e instanceof SocketException) { //sometimes this doesn't get caught by SDK
        return new TemporaryBackendException(message, e);
    }
    // unknown exception type
    return new PermanentBackendException(message, e);
}
 
Example #30
Source File: Transaction.java    From dynamodb-transactions with Apache License 2.0 4 votes vote down vote up
/**
 * Commits the transaction
 * 
 * @throws TransactionRolledBackException - the transaction was rolled back by a concurrent overlapping transaction
 * @throws UnknownCompletedTransactionException - the transaction completed, but it is not known whether it committed or rolled back
 * TODO throw a specific exception for encountering too much contention 
 */
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");
}