@DynamoDBVersionAttribute not allowed on Range key attribute

0

My table model in Java with DynamodbMapper annotation:

/**
 * Defines model for the DDB items stored in Documents table
 */
@Data // @Value not used as it cannot work with @NoArgsConstructor
@NoArgsConstructor // Required by DDBMapper for initialization
@AllArgsConstructor
@Builder(toBuilder = true)
@DynamoDBTable(tableName = DocumentModel.TABLE_NAME)
public class DocumentModel {

    public static final String TABLE_NAME = "Document";

    /**
     * Document id used to fetch a document's details.
     */
    @NonNull
    @DynamoDBHashKey
    @DynamoDBTypeConverted(converter = ACIConverter.class)
    private ACI id;

    /**
     * Version for a document, DDBMapper will update the version every time an overwrite of the same object occurs.
     */
    @DynamoDBRangeKey
    @DynamoDBVersionAttribute
    private int version;
}

I am trying to create a table with the model above using DynamoDBMapper. I am following the best practice: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html#bp-sort-keys-version-control by AWS for versioning objects in range key by using the annotation @DynamoDBVersionAttribute.
But when I try to run to build the table in tests using DynamoDBLocal I get the following error:

   [junit] Testsuite: com.amazon.dithreatmodelingservicelambda.database.DocumentDaoTest
    [junit] Tests run: 0, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.995 sec
    [junit]
    [junit] Testcase: com.amazon.dithreatmodelingservicelambda.database.DocumentDaoTest:	Caused an ERROR
    [junit] DocumentModel[version] could not be mapped for type int
    [junit] com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: DocumentModel[version] could not be mapped for type int
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:123)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:132)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:116)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$StandardTableFactory.getTable(StandardModelFactories.java:107)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.getTableModel(DynamoDBMapper.java:410)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper.generateCreateTableRequest(DynamoDBMapper.java:2270)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.AbstractDynamoDBMapper.generateCreateTableRequest(AbstractDynamoDBMapper.java:339)
    [junit] 	at com.amazon.dithreatmodelingservicelambda.tools.TestHelper.lambda$initializeDynamoDBMapper$0(TestHelper.java:31)
    [junit] 	at com.google.common.collect.ImmutableList.forEach(ImmutableList.java:406)
    [junit] 	at com.amazon.dithreatmodelingservicelambda.tools.TestHelper.initializeDynamoDBMapper(TestHelper.java:30)
    [junit] 	at com.amazon.dithreatmodelingservicelambda.database.DocumentDaoTest.classSetup(DocumentDaoTest.java:26)
    [junit] Caused by: com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: DocumentModel[version]; auto-generated key and ALWAYS not allowed
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperFieldModel$Builder.build(DynamoDBMapperFieldModel.java:427)
    [junit] 	at com.amazonaws.services.dynamodbv2.datamodeling.StandardModelFactories$TableBuilder.<init>(StandardModelFactories.java:121)
    [junit]
    [junit]
    [junit] TEST com.amazon.dithreatmodelingservicelambda.database.DocumentDaoTest FAILED
    [junit] Testsuite: com.amazon.dithreatmodelingservicelambda.database.ZonedDateTimeConverterTest
    [junit] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.018 sec
    [junit]
    [junit] Tests FAILED

Essentially this is the main error
"auto-generated key and ALWAYS not allowed"

After searching around the forum: https://forums.aws.amazon.com/message.jspa?messageID=312527 I found that AWS does not recommend auto-incrementing keys which the @DynamoDBVersionAttribute generates.

Why are there 2 conflicting guidances and if there is no conflict here then how can I enable optimistic locking on my range key attribute while using DynamoDBMapper?

drag
asked 5 years ago781 views
2 Answers
0
Accepted Answer

Hi,
I think you might be mixing two different concepts for the overloaded term "version".
The best practices guide for Using Sort Keys for Version Control: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html#bp-sort-keys-version-control
is more related to audit/compliance version control design pattern. Here, you are interested in two use cases:

1. Get the latest audit entry by using the sort key to search on "v0_"
2. Get the historical chronological list of audits, by using the partition key/sort key and filter out "v0_".

For this design pattern, you are NOT allowed to update/change historical audit data. You are only allowed to update "v0_Audit" so that the latest audit entry is available to auditors. When a new audit entry is made, the software must:

1. Insert a new audit entry row with sort key  "v<max version number + 1>_Audit"
2. Update the row with sort key "v0_Audit" with copy of the data inserted in step 1.

The DynamoDBMapper usage of DynamoDBVersionAttribute, is all about updating data and preventing two different clients from updating the same row in the table (optimistic locking). Each row will be updating the row version number on every new update. i.e. each client will initially get the current version for that row before updating the data. When the client attempts to update that existing row, the version the client has needs to match the version stored in the db for that row before it is saved. If the versions do NOT match, then the client's update will fail, which means that another client has already updated that row.

Hopefully, that makes sense,
-randy

EXPERT
answered 5 years ago
0

Got this answer from AWS support which echos the first answer on this threas

The DynamoDBMapper usage of DynamoDBVersionAttribute, is all about updating the same Item and preventing two different clients from updating the same Item in the table (optimistic locking). Each Client will be updating the Attribute version number for every new update. i.e. each client will initially get the current version for that item before updating the data. When the client attempts to update that existing item, the version the client has needs to match the version stored in the db for that item before it is saved.

Now since  with DynamoDB an item is uniquely characterized by it's key (whether partition key only, or partition + range keys together) and  DynamoDBMapper assigns a version number when you first save the object, and it automatically increments the version number each time you update the item hereby changing the range key. This will creates a new item in the table everytime which is technically not an update of the same Item but creates a new one always. which defects the purpose of optimistic locking in DynamoDB.


The Documentation here [1]. talks about using Sort key for Audit purposes were each update in the table is a new item ( a  Versions all existing in the same table)  using   composite primary key,  which uniquely identifies  an item in a table. While with optimistic locking[2], each item has an attribute that acts as a version number.(  Not Sort key as this will create a new item in the table ) If you retrieve an item from a table, the application records the version number of that item. You can update the item, but only if the version number on the server side has not changed. If there is a version mismatch, it means that someone else has modified the item before you did. The update attempt fails, because you have a stale version of the item. If this happens, you simply try again by retrieving the item and then trying to update it. Optimistic locking prevents you from accidentally overwriting changes that were made by others. It also prevents others from accidentally overwriting your changes.  

[1]. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-sort-keys.html#bp-sort-keys-version-control 
[2].https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html 
drag
answered 5 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions