@Override public Void create(Group group) { Item item = preparePutItem(group); PutItemSpec putItemSpec = new PutItemSpec() .withItem(item) .withConditionExpression("attribute_not_exists(#ns_key)") .withNameMap(new NameMap().with("#ns_key", HASH_KEY)); Table table = dynamoDB.getTable(groupTableName); final Supplier<PutItemOutcome> putItemOutcomeSupplier = () -> { try { return table.putItem(putItemSpec); } catch (ConditionalCheckFailedException e) { throwConflictAlreadyExists(group); return null; } }; return putItem(group, putItemOutcomeSupplier); }
@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(); } }
private boolean tryAddMissingPartition(String dyanmoDBTaableName,DynamoDB dynamoDBClient, Partition partition){ Table ddbTable= dynamoDBClient.getTable(dyanmoDBTaableName); Item item=new Item() .withPrimaryKey("PartitionSpec",partition.spec()) .withString("PartitionPath",partition.path()) .withString("PartitionName", partition.name()); PutItemSpec itemSpec=new PutItemSpec() .withItem(item) .withConditionExpression("attribute_not_exists(#ps)") .withNameMap(new NameMap() .with("#ps","PartitionSpec")); try{ ddbTable.putItem(itemSpec); System.out.println("Item was added to the table.PartitionSpec="+partition.spec()+"; Path="+partition.path()); return true; } catch(ConditionalCheckFailedException e){ System.out.println(e.toString()); System.out.println("Item already exists. PartitionSpec="+partition.spec()+"; Path="+partition.path()); return false; } }
@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(); } }
@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); }
@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); }
boolean createItemIfNotExists(String key, long currentTimeMillis, Context context) { LambdaLogger logger = context.getLogger(); AmazonDynamoDB client = createDynamoDBClient(cc); String functionName = context.getFunctionName(); try { // Create a record if it does not exist PutItemRequest req = new PutItemRequest().withTableName(TABLE_NAME) .addItemEntry(COL_FUNCTION_NAME, new AttributeValue(functionName)) .addItemEntry(COL_KEY, new AttributeValue(key)) .addItemEntry(COL_CREATED_TIME, new AttributeValue().withN(Long.toString(currentTimeMillis))) .addExpectedEntry(COL_FUNCTION_NAME, new ExpectedAttributeValue().withExists(false)) .addExpectedEntry(COL_KEY, new ExpectedAttributeValue().withExists(false)); client.putItem(req); return true; } catch (ConditionalCheckFailedException e) { logger.log("Record exsited. functionName[" + functionName + "] key[" + key + "]"); return false; } finally { client.shutdown(); } }
@Override public void putItemOrThrow(T item) { try { Expected[] expected; if ( null == _rkName ) { expected = new Expected[]{ new Expected(_hkName).notExist() }; } else { expected = new Expected[]{ new Expected(_hkName).notExist(), new Expected(_rkName).notExist() }; } maybeBackoff(false, () -> _putItem.putItem(_encryption.encrypt(toItem(item)), expected)); } catch ( ConditionalCheckFailedException ex ) { throw new EntityExistsException(ex); } }
@Override public void transform(Item scoreItem, DynamoDB dynamodb) { String playerName = scoreItem.getString(PLAYER_NAME); int score = scoreItem.getInt(SCORE); String date = scoreItem.getString(DATE); Table table = dynamodb.getTable(HIGH_SCORES_BY_DATE_TABLE_NAME); // Use conditional write to update max score UpdateItemExpressionSpec updateMax = new ExpressionSpecBuilder() .withCondition(N(MAX_SCORE).lt(score) .or(attribute_not_exists(MAX_SCORE))) .addUpdate(N(MAX_SCORE).set(score)) .buildForUpdate(); try { table.updateItem(PLAYER_NAME, playerName, DATE, date, updateMax); } catch (ConditionalCheckFailedException ccfe) {} }
@Override public <T extends Message> boolean delete(T item, Modifier... modifiers) throws DataStoreException { DynamoClassMapping<T> tableInfo = getClassMapping(item); log.debug("Delete {}", item); for (Modifier modifier : modifiers) { throw new UnsupportedOperationException(); } DeleteItemRequest request = new DeleteItemRequest(); request.setTableName(tableInfo.getDynamoTableName()); request.setKey(tableInfo.buildCompleteKey(item)); request.setConditionExpression("attribute_exists(hash_key)"); try { DeleteItemResult response = dynamoDB.deleteItem(request); return true; } catch (ConditionalCheckFailedException e) { return false; } }
@Override public Void createFeature(Feature feature) { final String key = feature.getKey(); final String group = feature.getGroup(); final Item item = preparePutItem(feature); final PutItemSpec putItemSpec = new PutItemSpec() .withItem(item) .withConditionExpression("attribute_not_exists(#featurekey)") .withNameMap(new NameMap().with("#featurekey", RANGE_KEY)); final Supplier<PutItemOutcome> putItemOutcomeSupplier = () -> { try { return dynamoDB.getTable(featureTableName).putItem(putItemSpec); } catch (ConditionalCheckFailedException e) { logger.error("err=conflict_feature_already_exists feature_key={} {}", feature.getKey(), e.getMessage()); throwConflictAlreadyExists(feature); return null; } }; final DynamoDbCommand<PutItemOutcome> cmd = new DynamoDbCommand<>("createFeature", putItemOutcomeSupplier, () -> { throw new RuntimeException("createFeature"); }, hystrixWriteConfiguration, metrics); final PutItemOutcome outcome = cmd.execute(); logger.info("{} /dynamodb_put_item_result=[{}]", kvp("op", "createFeature", HASH_KEY, group, RANGE_KEY, key, "result", "ok"), outcome.getPutItemResult().toString()); return null; }
boolean updateItem(String key, long currentTimeMillis, int expiredIntervalMillis, Context context) { AmazonDynamoDB client = createDynamoDBClient(cc); String functionName = context.getFunctionName(); try { long sec = currentTimeMillis - expiredIntervalMillis; DynamoDB dynamoDB = new DynamoDB(client); Table table = dynamoDB.getTable(TABLE_NAME); Map<String, String> expressionAttributeNames = new HashMap<>(); expressionAttributeNames.put("#created_time", COL_CREATED_TIME); Map<String, Object> expressionAttributeValues = new HashMap<>(); expressionAttributeValues.put(":now", currentTimeMillis); expressionAttributeValues.put(":expired", sec); table.updateItem(new PrimaryKey(COL_FUNCTION_NAME, functionName, COL_KEY, key), "set #created_time = :now", // UpdateExpression "#created_time < :expired", // ConditionExpression expressionAttributeNames, expressionAttributeValues); return true; } catch (ConditionalCheckFailedException e) { return false; } finally { client.shutdown(); } }
/** * Inserting the food into the database, dislike and like are set to 0 * @param food */ public static void insertFood(FoodReceive food){ Log.d(LOG_TAG, "Inserting: " + food.getName()); final DynamoDBMapper mapper = AWSMobileClient.defaultMobileClient().getDynamoDBMapper(); final FoodDO firstItem = new FoodDO(); firstItem.setFoodId(food.getFood_id()); firstItem.setRestaurantId(food.getLocation().getRestaurantId()); firstItem.setName(food.getName()); AmazonClientException lastException = null; DynamoDBSaveExpression saveExpression = new DynamoDBSaveExpression(); Map<String, ExpectedAttributeValue> expectedAttributes = ImmutableMapParameter.<String, ExpectedAttributeValue>builder() .put("foodId", new ExpectedAttributeValue(false)).build(); saveExpression.setExpected(expectedAttributes); try { // mapper.save(firstItem); mapper.save(firstItem, saveExpression); } catch (ConditionalCheckFailedException e){ Log.e(LOG_TAG,"The foodId exists: " + e.getMessage()); lastException = e; } catch (final AmazonClientException ex) { Log.e(LOG_TAG,"Failed saving item batch: " + ex.getMessage()); lastException = ex; } if (lastException != null) { // Re-throw the last exception encountered to alert the user. throw lastException; } Log.d(LOG_TAG, "Insert successful"); }
private <V> V updateItem(UpdateItemSpec updateItemSpec, Class<V> type) { try { return maybeBackoff(false, () -> fromItem(_encryption.decrypt(_updateItem.updateItem(updateItemSpec).getItem()), type)); } catch ( ConditionalCheckFailedException ex ) { throw new RollbackException(ex); } }
/** * Acquires a distributed lock, returning true if it was acquired, false otherwise * * The lock, if acquired, has the passed expiry period in seconds. This means if another process attempts to * aquire it, it will fail until now + expiryInSeconds, after which time it will succeed. This prevents the lock * from being permanently locked, in case the acquiring process fails to release it for whatever reason. * * This is an atomic operation, only one process can acquire a lock at a time - if two processes contend * for a lock, only one will ever get a return value of true from this method. */ @Override public boolean tryLock(String lockKey, int expiryInSeconds) { try { lockKey = getEnvironmentSpecificLockKey(lockKey); logger.info("Trying to acquire lock [{}]", lockKey); Table table = dynamoDb.getTable(tableName); Item lock = new Item() .withPrimaryKey(TABLE_KEY, lockKey) .withLong(LOCK, clock.millis() + (expiryInSeconds * 1000L)) .withString(TABLE_CREATED_AT, OffsetDateTime.now(clock).toString()); // create the lock if it doesn't exist, OR overwrite it if it's expired table.putItem( lock, "attribute_not_exists(#id) OR #lockExpiry < :now", ImmutableMap.of("#id", TABLE_KEY, "#lockExpiry", LOCK), ImmutableMap.of(":now", clock.millis()) ); logger.info("Acquired lock [{}]", lockKey); return true; } catch (ConditionalCheckFailedException e) { // thrown if we tried to acquire a locked lock logger.info("Could not acquire locked lock [{}]", lockKey); } catch (Exception ex) { // thrown on any other, unexpected, error performing the request logger.error("Error when trying to aquire lock [{}]: ", lockKey, ex); } return false; }
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); }
@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; }
@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); }
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<String, AttributeValue>(); ddbKey.put(DEFAULT_HASH_KEY, item.get(DEFAULT_HASH_KEY)); ddbKey.put(DEFAULT_RANGE_KEY, item.get(DEFAULT_RANGE_KEY)); return ddbGet(ddbKey); } }
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); } }
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"); } }
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"); } }
@Override public <T extends Message> void insert(T item, Modifier... modifiers) throws DataStoreException { DynamoClassMapping<T> tableInfo = getClassMapping(item); log.debug("Insert {} {}", item.getClass().getSimpleName(), item); for (Modifier modifier : modifiers) { throw new UnsupportedOperationException(); } PutItemRequest request = new PutItemRequest(); request.setTableName(tableInfo.getDynamoTableName()); Map<String, AttributeValue> itemData = tableInfo.mapToDb(item); request.setItem(itemData); Map<String, ExpectedAttributeValue> expected = Maps.newHashMap(); expected.put(FIELD_HASH_KEY, new ExpectedAttributeValue().withComparisonOperator(ComparisonOperator.NULL)); request.setExpected(expected); if (expected.size() > 1) { request.setConditionalOperator(ConditionalOperator.AND); } try { dynamoDB.putItem(request); } catch (ConditionalCheckFailedException e) { log.debug("Insert failed {}", item, e); throw new UniqueIndexViolation(null); } }
@Override public Void updateFeature(Feature feature, FeatureVersion previousVersion) { logger.info("{}", kvp("op", "updateFeature", HASH_KEY, feature.getGroup(), RANGE_KEY, feature.getKey())); final String key = feature.getKey(); final String group = feature.getGroup(); final Item item = preparePutItem(feature); final PutItemSpec putItemSpec = new PutItemSpec() .withItem(item) .withExpected( new Expected("version_timestamp").eq(previousVersion.getTimestamp()), new Expected("version_counter").eq(previousVersion.getCounter()) ); final Supplier<PutItemOutcome> putItemOutcomeSupplier = () -> { try { return dynamoDB.getTable(featureTableName).putItem(putItemSpec); } catch (ConditionalCheckFailedException e) { logger.error("err=conflict_feature_version_mismatch feature_key={} {}", feature.getKey(), e.getMessage()); throwConflictVersionMismatch(feature); return null; } }; final DynamoDbCommand<PutItemOutcome> cmd = new DynamoDbCommand<>("updateFeature", putItemOutcomeSupplier, () -> { throw new RuntimeException("updateFeature"); }, hystrixWriteConfiguration, metrics); final PutItemOutcome outcome = cmd.execute(); logger.info("{} /dynamodb_update_item_result=[{}]", kvp("op", "updateFeature", HASH_KEY, group, RANGE_KEY, key, "result", "ok"), outcome.getPutItemResult().toString()); return null; }
/** * returns 'true' if output file was generated, 'false' otherwise */ public boolean updateFromFile(boolean useConditionalUpdate) throws Exception { String correctionFilePath = options.getCorrectionInputPath(); PrintHelper.printUpdateStartInfo(correctionFilePath); if (options.isCorrectionInputS3Path()) { correctionFilePath = options.getTmpCorrectionInputPath(); } loadRecordsFromCorrectionFile(correctionFilePath); checkUseConditionalUpdate(useConditionalUpdate); // Used to create correction output file only if an error occurs boolean isCorrectionOutputFileGenerated = false; try { while (correctionReader.moveToNextRecordIfHas()) { try { Map<String, AttributeValue> primaryKey = genTablePrimaryKeyForRecord(); Map<String, AttributeValueUpdate> updateItems = genUpdateItemsForRecord(); Map<String, ExpectedAttributeValue> expectedItems = null; if (useConditionalUpdate) { expectedItems = genExpectedItemsForRecord(updateItems); } if(tableWriter.sendUpdateRequest(primaryKey, updateItems, expectedItems)) { successfulUpdates++; } } catch(Exception e) { if(e instanceof ConditionalCheckFailedException) { conditionalUpdateFailures++; } else { unexpectedErrors++; } // generate output file if it does not exist if(!isCorrectionOutputFileGenerated) { createViolationWriter(); isCorrectionOutputFileGenerated = true; // Add header to the output file List<String> correctionOutputHeader = new ArrayList<String>(correctionReader.getHeader()); correctionOutputHeader.add(ViolationRecord.GSI_VALUE_UPDATE_ERROR); // Add another column for error ViolationWriter.getInstance().addViolationRecord(correctionOutputHeader); } List<String> failedRecord = new ArrayList<String>(correctionReader.getCurrentRecord()); // Add error to the record failedRecord.add(correctionReader.getHeader().size(), e.getMessage()); ViolationWriter.getInstance().addViolationRecord(failedRecord); } } } finally { // close the file if(isCorrectionOutputFileGenerated) { ViolationWriter.getInstance().flushAndCloseWriter(); } } if(useConditionalUpdate) { PrintHelper.printCorrectionSummary(violationUpdateRequests, successfulUpdates, conditionalUpdateFailures, unexpectedErrors, options.getCorrectionOutputPath()); } else { PrintHelper.printCorrectionSummary(violationUpdateRequests, successfulUpdates, unexpectedErrors, options.getCorrectionOutputPath()); } if(conditionalUpdateFailures > 0 || unexpectedErrors > 0) { return true; } return false; }
public UpdateItemResult updateConditionalValue(final AmazonDynamoDB dynamoClient, final String tableName, final UpdateKey key, final String attribute, final AggregateAttributeModification update) throws Exception { Map<String, AttributeValue> updateKey = StreamAggregatorUtils.getTableKey(key); UpdateItemResult result; final ReturnValue returnValue = ReturnValue.UPDATED_NEW; final String setAttribute = StreamAggregatorUtils.methodToColumn(attribute); // create the update that we want to write final Map<String, AttributeValueUpdate> thisCalcUpdate = new HashMap<String, AttributeValueUpdate>() { { put(setAttribute, new AttributeValueUpdate().withAction(AttributeAction.PUT).withValue( new AttributeValue().withN("" + update.getFinalValue()))); } }; // create the request UpdateItemRequest req = new UpdateItemRequest().withTableName(tableName).withKey(updateKey).withReturnValues( returnValue).withAttributeUpdates(thisCalcUpdate); Map<String, ExpectedAttributeValue> expected = new HashMap<>(); final SummaryCalculation calc = update.getCalculationApplied(); // try an update to PUT the value if NOT EXISTS, to establish if we // are the first writer for this key expected = new HashMap<String, ExpectedAttributeValue>() { { put(setAttribute, new ExpectedAttributeValue().withExists(false)); } }; req.setExpected(expected); try { result = DynamoUtils.updateWithRetries(dynamoClient, req); // yay - we were the first writer, so our value was written return result; } catch (ConditionalCheckFailedException e1) { // set the expected to the comparison contained in the update // calculation expected.clear(); expected.put( setAttribute, new ExpectedAttributeValue().withComparisonOperator( calc.getDynamoComparisonOperator()).withValue( new AttributeValue().withN("" + update.getFinalValue()))); req.setExpected(expected); // do the conditional update on the summary // calculation. this may result in no update being // applied because the new value is greater than the // current minimum for MIN, or less than the current // maximum for MAX. try { result = DynamoUtils.updateWithRetries(dynamoClient, req); return result; } catch (ConditionalCheckFailedException e2) { // no worries - we just weren't the min or max! return null; } } }
@Override public <T extends Message> boolean update(T item, Modifier... modifiers) throws DataStoreException { DynamoClassMapping<T> tableInfo = getClassMapping(item); log.debug("Update {} {} [{}]", item.getClass().getSimpleName(), item, modifiers); UpdateItemRequest request = new UpdateItemRequest(); request.setTableName(tableInfo.getDynamoTableName()); request.setKey(tableInfo.buildCompleteKey(item)); Map<String, ExpectedAttributeValue> expected = Maps.newHashMap(); expected.put(FIELD_HASH_KEY, new ExpectedAttributeValue().withComparisonOperator(ComparisonOperator.NOT_NULL)); for (Modifier modifier : modifiers) { if (modifier instanceof WhereModifier) { WhereModifier where = (WhereModifier) modifier; Map<FieldDescriptor, Object> matcherFields = where.getMatcher().getAllFields(); for (Map.Entry<FieldDescriptor, Object> matcherField : matcherFields.entrySet()) { FieldDescriptor fieldDescriptor = matcherField.getKey(); Object fieldValue = matcherField.getValue(); tableInfo.addFilter(expected, fieldDescriptor, fieldValue); } } else { throw new UnsupportedOperationException(); } } Map<String, AttributeValueUpdate> attributeUpdates = tableInfo.mapToUpdate(item); request.setAttributeUpdates(attributeUpdates); request.setExpected(expected); if (expected.size() > 1) { request.setConditionalOperator(ConditionalOperator.AND); } try { UpdateItemResult response = dynamoDB.updateItem(request); return true; } catch (ConditionalCheckFailedException e) { log.debug("Update failed (conditional check failed)"); return false; } }