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

The following examples show how to use com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue. 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: 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 #2
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 #3
Source File: MetaStore.java    From aws-dynamodb-encryption-java with Apache License 2.0 6 votes vote down vote up
/**
 * Create a new MetaStore with specified table name and extra data supplier.
 *
 * @param ddb Interface for accessing DynamoDB.
 * @param tableName DynamoDB table name for this {@link MetaStore}.
 * @param encryptor used to perform crypto operations on the record attributes
 * @param extraDataSupplier provides extra data that should be stored along with the material.
 */
public MetaStore(final AmazonDynamoDB ddb, final String tableName,
        final DynamoDBEncryptor encryptor, final ExtraDataSupplier extraDataSupplier) {
    this.ddb = checkNotNull(ddb, "ddb must not be null");
    this.tableName = checkNotNull(tableName, "tableName must not be null");
    this.encryptor = checkNotNull(encryptor, "encryptor must not be null");
    this.extraDataSupplier = checkNotNull(extraDataSupplier, "extraDataSupplier must not be null");

    this.ddbCtx = new EncryptionContext.Builder().withTableName(this.tableName)
            .withHashKeyName(DEFAULT_HASH_KEY).withRangeKeyName(DEFAULT_RANGE_KEY).build();

    final Map<String, ExpectedAttributeValue> tmpExpected = new HashMap<>();
    tmpExpected.put(DEFAULT_HASH_KEY, new ExpectedAttributeValue().withExists(false));
    tmpExpected.put(DEFAULT_RANGE_KEY, new ExpectedAttributeValue().withExists(false));
    doesNotExist = Collections.unmodifiableMap(tmpExpected);

    this.doNotEncrypt = getSignedOnlyFields(extraDataSupplier);
}
 
Example #4
Source File: SingleExpectedAttributeValueBuilder.java    From dynamodb-janusgraph-storage-backend with Apache License 2.0 6 votes vote down vote up
private void addExpectedValueIfPresent(final StaticBuffer column, final Map<String, ExpectedAttributeValue> expectedValueMap) {
    final String dynamoDbColumn = encodeKeyBuffer(column);

    if (expectedValueMap.containsKey(dynamoDbColumn)) {
        return;
    }

    if (transaction.contains(store, key, column)) {
        final StaticBuffer expectedValue = transaction.get(store, key, column);
        final ExpectedAttributeValue expectedAttributeValue;
        if (expectedValue == null) {
            expectedAttributeValue = new ExpectedAttributeValue().withExists(false);
        } else {
            final AttributeValue attributeValue = encodeValue(expectedValue);
            expectedAttributeValue = new ExpectedAttributeValue().withValue(attributeValue)
                                                                 .withComparisonOperator(ComparisonOperator.EQ);
        }
        expectedValueMap.put(dynamoDbColumn, expectedAttributeValue);
    }
}
 
Example #5
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 #6
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 #7
Source File: TransactionDynamoDBFacadeTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void testCheckExpectedStringValueWithMatchingItem() {
    Map<String, AttributeValue> item = Collections.singletonMap("Foo", new AttributeValue("Bar"));
    Map<String, ExpectedAttributeValue> expected = Collections.singletonMap("Foo", new ExpectedAttributeValue(new AttributeValue("Bar")));

    TransactionDynamoDBFacade.checkExpectedValues(expected, item);
    // no exception expected
}
 
Example #8
Source File: TransactionDynamoDBFacadeTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void testCheckExpectedBinaryValueWithMatchingItem() {
    Map<String, AttributeValue> item = Collections.singletonMap("Foo", new AttributeValue().withB(ByteBuffer.wrap(new byte[] { 1, 127, -127 })));
    Map<String, ExpectedAttributeValue> expected = Collections.singletonMap("Foo", new ExpectedAttributeValue(new AttributeValue().withB(ByteBuffer.wrap(new byte[] { 1, 127, -127 }))));

    TransactionDynamoDBFacade.checkExpectedValues(expected, item);
    // no exception expected
}
 
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: TransactionDynamoDBFacadeTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void testCheckExpectedNumericValueWithMatchingItem() {
    Map<String, AttributeValue> item = Collections.singletonMap("Foo", new AttributeValue().withN("3.14"));
    Map<String, ExpectedAttributeValue> expected = Collections.singletonMap("Foo", new ExpectedAttributeValue(new AttributeValue().withN("3.14")));

    TransactionDynamoDBFacade.checkExpectedValues(expected, item);
    // no exception expected
}
 
Example #11
Source File: TransactionDynamoDBFacade.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Override
public UpdateItemResult updateItem(UpdateItemRequest request)
        throws AmazonServiceException, AmazonClientException {
    Map<String, ExpectedAttributeValue> expectedValues = request.getExpected();
    checkExpectedValues(request.getTableName(), request.getKey(), expectedValues);

    // conditional checks are handled by the above call
    request.setExpected(null);
    return txn.updateItem(request);
}
 
Example #12
Source File: TransactionDynamoDBFacade.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Override
public PutItemResult putItem(PutItemRequest request)
        throws AmazonServiceException, AmazonClientException {
    Map<String, ExpectedAttributeValue> expectedValues = request.getExpected();
    checkExpectedValues(request.getTableName(), Request.getKeyFromItem(request.getTableName(),
            request.getItem(), txManager), expectedValues);

    // conditional checks are handled by the above call
    request.setExpected(null);
    return txn.putItem(request);
}
 
Example #13
Source File: TransactionDynamoDBFacadeTest.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Test
public void testCheckExpectedNumericValueWithMatchingNotStringEqualItem() {
    Map<String, AttributeValue> item = Collections.singletonMap("Foo", new AttributeValue().withN("3.140"));
    Map<String, ExpectedAttributeValue> expected = Collections.singletonMap("Foo", new ExpectedAttributeValue(new AttributeValue().withN("3.14")));

    TransactionDynamoDBFacade.checkExpectedValues(expected, item);
    // no exception expected
}
 
Example #14
Source File: TransactionDynamoDBFacade.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
@Override
public DeleteItemResult deleteItem(DeleteItemRequest request)
        throws AmazonServiceException, AmazonClientException {
    Map<String, ExpectedAttributeValue> expectedValues = request.getExpected();
    checkExpectedValues(request.getTableName(), request.getKey(), expectedValues);

    // conditional checks are handled by the above call
    request.setExpected(null);
    return txn.deleteItem(request);
}
 
Example #15
Source File: Request.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a new copy of Map that can be used in a write on the item to ensure it exists 
 * @param txManager
 * @return a map for use in an expected clause to ensure the item exists
 */
@JsonIgnore
protected Map<String, ExpectedAttributeValue> getExpectExists(TransactionManager txManager) {
    Map<String, AttributeValue> key = getKey(txManager);
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(key.size());
    for(Map.Entry<String, AttributeValue> entry : key.entrySet()) {
        expected.put(entry.getKey(), new ExpectedAttributeValue().withValue(entry.getValue()));
    }
    return expected;
}
 
Example #16
Source File: Request.java    From dynamodb-transactions with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a new copy of Map that can be used in a write on the item to ensure it does not exist 
 * @param txManager
 * @return a map for use in an expected clause to ensure the item does not exist
 */
@JsonIgnore
protected Map<String, ExpectedAttributeValue> getExpectNotExists(TransactionManager txManager) {
    Map<String, AttributeValue> key = getKey(txManager);
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>(key.size());
    for(Map.Entry<String, AttributeValue> entry : key.entrySet()) {
        expected.put(entry.getKey(), new ExpectedAttributeValue().withExists(false));
    }
    return expected;
}
 
Example #17
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 #18
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 #19
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 #20
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 #21
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 #22
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 #23
Source File: SingleExpectedAttributeValueBuilder.java    From dynamodb-janusgraph-storage-backend with Apache License 2.0 5 votes vote down vote up
public Map<String, ExpectedAttributeValue> build(final KCVMutation mutation) {
    final Map<String, ExpectedAttributeValue> expected = Maps.newHashMapWithExpectedSize(mutation.getTotalMutations());

    for (Entry addedColumn : mutation.getAdditions()) {
        final StaticBuffer columnKey = addedColumn.getColumn();
        addExpectedValueIfPresent(columnKey, expected);
    }

    for (StaticBuffer deletedKey : mutation.getDeletions()) {
        addExpectedValueIfPresent(deletedKey, expected);
    }

    return expected;
}
 
Example #24
Source File: DynamoDbSingleRowStore.java    From dynamodb-janusgraph-storage-backend with Apache License 2.0 5 votes vote down vote up
@Override
public Collection<MutateWorker> createMutationWorkers(final Map<StaticBuffer, KCVMutation> mutationMap, final DynamoDbStoreTransaction txh) {

    final List<MutateWorker> workers = Lists.newLinkedList();

    for (Map.Entry<StaticBuffer, KCVMutation> entry : mutationMap.entrySet()) {
        final StaticBuffer hashKey = entry.getKey();
        final KCVMutation mutation = entry.getValue();

        final Map<String, AttributeValue> key = new ItemBuilder().hashKey(hashKey)
                                                           .build();

        // Using ExpectedAttributeValue map to handle large mutations in a single request
        // Large mutations would require multiple requests using expressions
        final Map<String, ExpectedAttributeValue> expected =
            new SingleExpectedAttributeValueBuilder(this, txh, hashKey).build(mutation);

        final Map<String, AttributeValueUpdate> attributeValueUpdates =
            new SingleUpdateBuilder().deletions(mutation.getDeletions())
                .additions(mutation.getAdditions())
                .build();

        final UpdateItemRequest request = super.createUpdateItemRequest()
               .withKey(key)
               .withReturnValues(ReturnValue.ALL_NEW)
               .withAttributeUpdates(attributeValueUpdates)
               .withExpected(expected);

        final MutateWorker worker;
        if (mutation.hasDeletions() && !mutation.hasAdditions()) {
            worker = new SingleUpdateWithCleanupWorker(request, client.getDelegate());
        } else {
            worker = new UpdateItemWorker(request, client.getDelegate());
        }
        workers.add(worker);
    }
    return workers;
}
 
Example #25
Source File: GenericDynamoDB.java    From strongbox with Apache License 2.0 5 votes vote down vote up
private Map<String, ExpectedAttributeValue> expectExists(Entry entry) {
    Map<String, ExpectedAttributeValue> expected = new HashMap<>();

    ExpectedAttributeValue expectedAttributeValue = new ExpectedAttributeValue(true);
    expectedAttributeValue.setValue(new AttributeValue(getPartitionKeyValue(entry)));
    expected.put(partitionKeyName.toString(), expectedAttributeValue);

    // FIXME: hardcode whole file, or make generic
    ExpectedAttributeValue expectedSha = new ExpectedAttributeValue(true);
    expectedSha.setValue(new AttributeValue(sha(entry)));
    expected.put(OPTIMISTIC_LOCK_FIELD_NAME, expectedSha);

    return expected;
}
 
Example #26
Source File: GenericDynamoDB.java    From strongbox with Apache License 2.0 5 votes vote down vote up
private void executeUpdate(Map<String, AttributeValue> keys, Map<String, AttributeValueUpdate> attributes, Map<String, ExpectedAttributeValue> expected) {
    UpdateItemRequest updateEntry = new UpdateItemRequest()
            .withTableName(tableName)
            .withKey(keys)
            .withAttributeUpdates(attributes)
            .withExpected(expected);

    client.updateItem(updateEntry);
}
 
Example #27
Source File: TransactionItem.java    From dynamodb-transactions with Apache License 2.0 4 votes vote down vote up
/**
 * Adds a request object (input param) to the transaction item.  Enforces that request are unique for a given table name and primary key.
 * Doesn't let you do more than one write per item.  However you can upgrade a read lock to a write.
 * @param callerRequest 
 * @throws ConditionalCheckFailedException if the tx item changed out from under us.  If you get this you must throw this TransactionItem away.
 * @throws DuplicateRequestException If you get this you do not need to throw away the item.
 * @throws InvalidRequestException If the request would add too much data to the transaction
 * @return true if the request was added, false if it didn't need to be added (because it was a duplicate lock request)
 */
public synchronized boolean addRequest(Request callerRequest) throws ConditionalCheckFailedException, DuplicateRequestException {
    // 1. Ensure the request is unique (modifies the internal data structure if it is unique)
    //    However, do not not short circuit.  If we're doing a read in a resumed transaction, it's important to ensure we're returning
    //    any writes that happened before. 
    addRequestToMap(callerRequest);
    
    callerRequest.setRid(version);
    
    // 2. Write request to transaction item
    ByteBuffer requestBytes = Request.serialize(txId, callerRequest);
    AttributeValueUpdate txItemUpdate = new AttributeValueUpdate()
        .withAction(AttributeAction.ADD)
        .withValue(new AttributeValue().withBS(Arrays.asList(requestBytes)));
    
    Map<String, AttributeValueUpdate> txItemUpdates = new HashMap<String, AttributeValueUpdate>();
    txItemUpdates.put(AttributeName.REQUESTS.toString(), txItemUpdate);    
    txItemUpdates.put(AttributeName.VERSION.toString(), new AttributeValueUpdate().withAction(AttributeAction.ADD).withValue(new AttributeValue().withN("1")));
    txItemUpdates.put(AttributeName.DATE.toString(), new AttributeValueUpdate().withAction(AttributeAction.PUT).withValue(txManager.getCurrentTimeAttribute()));
    
    Map<String, ExpectedAttributeValue> expected = new HashMap<String, ExpectedAttributeValue>();
    expected.put(AttributeName.STATE.toString(), new ExpectedAttributeValue(new AttributeValue(STATE_PENDING)));
    expected.put(AttributeName.VERSION.toString(), new ExpectedAttributeValue(new AttributeValue().withN(Integer.toString(version))));
    
    UpdateItemRequest txItemUpdateRequest = new UpdateItemRequest()
        .withTableName(txManager.getTransactionTableName())
        .withKey(txKey)
        .withExpected(expected)
        .withReturnValues(ReturnValue.ALL_NEW)
        .withAttributeUpdates(txItemUpdates);
    
    try {
        txItem = txManager.getClient().updateItem(txItemUpdateRequest).getAttributes();
        int newVersion = Integer.parseInt(txItem.get(AttributeName.VERSION.toString()).getN());
        txAssert(newVersion == version + 1, txId, "Unexpected version number from update result");
        version = newVersion;
    } catch (AmazonServiceException e) {
        if("ValidationException".equals(e.getErrorCode())) {
            removeRequestFromMap(callerRequest);
            throw new InvalidRequestException("The amount of data in the transaction cannot exceed the DynamoDB item size limit", 
                txId, callerRequest.getTableName(), callerRequest.getKey(txManager), callerRequest);
        } else {
            throw e;
        }
    }
    return true;
}
 
Example #28
Source File: GenericDynamoDBTest.java    From strongbox with Apache License 2.0 4 votes vote down vote up
private UpdateItemRequest constructUpdateItemRequest(RawSecretEntry rawSecretEntry, boolean expectExists, Optional<RawSecretEntry> expectedRawSecretEntry) {
    // Create item key.
    Map<String, AttributeValue> key = new HashMap<>();
    key.put(KEY_ATTRIBUTE_NAME.toString(), new AttributeValue().withS(rawSecretEntry.secretIdentifier.name));
    key.put(VERSION_ATTRIBUTE_NAME.toString(), new AttributeValue().withN(String.valueOf(rawSecretEntry.version)));


    // Create item attributes.
    Map<String, AttributeValueUpdate> attributes = new HashMap<>();
    attributes.put(SCHEMA_VERSION_FIELD_NAME,
            new AttributeValueUpdate()
                    .withAction(AttributeAction.PUT)
                    .withValue(new AttributeValue()
                            .withN(SCHEMA_VERSION)));

    attributes.put(NOT_BEFORE_ATTRIBUTE_NAME.toString(),
            new AttributeValueUpdate()
                    .withAction(AttributeAction.PUT)
                    .withValue(new AttributeValue()
                            .withN(FormattedTimestamp.epoch(rawSecretEntry.notBefore.get()).toString())));
    attributes.put(STATE_ATTRIBUTE_NAME.toString(),
            new AttributeValueUpdate()
                    .withAction(AttributeAction.PUT)
                    .withValue(new AttributeValue()
                            .withN(Byte.toString(rawSecretEntry.state.asByte()))));
    attributes.put(VALUE_ATTRIBUTE_NAME.toString(),
            new AttributeValueUpdate()
                    .withAction(AttributeAction.PUT)
                    .withValue(new AttributeValue()
                            .withS(Encoder.base64encode(rawSecretEntry.encryptedPayload))));
    attributes.put(OPTIMISTIC_LOCKING_ATTRIBUTE_NAME,
            new AttributeValueUpdate()
                    .withAction(AttributeAction.PUT)
                    .withValue(new AttributeValue()
                            .withS(Encoder.base64encode(rawSecretEntry.sha1OfEncryptionPayload()))));

    // Create the expected conditions map.
    Map<String, ExpectedAttributeValue> expected = new HashMap<>();
    if (expectExists) {
        expected.put(KEY_ATTRIBUTE_NAME.toString(), new ExpectedAttributeValue(true).withValue(
                new AttributeValue(rawSecretEntry.secretIdentifier.name)));
        expected.put(OPTIMISTIC_LOCKING_ATTRIBUTE_NAME, new ExpectedAttributeValue(true).withValue(
                new AttributeValue(Encoder.sha1(expectedRawSecretEntry.get().encryptedPayload))));
    } else {
        expected.put(KEY_ATTRIBUTE_NAME.toString(), new ExpectedAttributeValue(false));
    }

    return new UpdateItemRequest(tableName, key, attributes).withExpected(expected);
}
 
Example #29
Source File: GenericDynamoDB.java    From strongbox with Apache License 2.0 4 votes vote down vote up
private Map<String, ExpectedAttributeValue> expectNotExists() {
    Map<String, ExpectedAttributeValue> expected = new HashMap<>();
    expected.put(partitionKeyName.toString(), new ExpectedAttributeValue(false));
    return expected;
}