Skip to content

Comments

[POC] Optimistic Locking for Delete Operations#6455

Draft
anasatirbasa wants to merge 1 commit intoaws:masterfrom
anasatirbasa:poc/optimistic-locking-for-delete-operations
Draft

[POC] Optimistic Locking for Delete Operations#6455
anasatirbasa wants to merge 1 commit intoaws:masterfrom
anasatirbasa:poc/optimistic-locking-for-delete-operations

Conversation

@anasatirbasa
Copy link
Contributor

@anasatirbasa anasatirbasa commented Sep 29, 2025

Description

Adds explicit optimistic locking support for delete operations in the DynamoDB Enhanced Client, while preserving full backward compatibility.

Until now, deleteItem operations did not automatically apply version-based conditional checks, even when a record was annotated with @DynamoDbVersionAttribute. This created an inconsistency with putItem and updateItem, which already integrate optimistic locking via VersionedRecordExtension.

Default behavior remains unchanged.
Deletes are still unconditional unless optimistic locking is explicitly enabled.


Motivation and Context

This PR addresses community request #2358, where users expected delete operations to respect optimistic locking semantics similar to put/update operations.

An earlier attempt (PR #6043) proposed implicitly enabling version checks on deletes. However, this risked breaking existing applications that relied on unconditional deletes even when using @DynamoDbVersionAttribute.

To preserve backward compatibility, this PR introduces explicit opt-in optimistic locking.


What This PR Introduces

1. Boolean Overloads (Sync & Async)

New overloads allow explicit control of optimistic locking behavior:

  • T deleteItem(T keyItem, boolean useOptimisticLocking);
  • CompletableFuture<T> deleteItem(T keyItem, boolean useOptimisticLocking);

Usage:

// Unconditional delete (default behavior)
table.deleteItem(item, false);

// Optimistic locking enabled
table.deleteItem(item, true);

The existing deleteItem(T keyItem) method is now deprecated and delegates to deleteItem(keyItem, false).


2. Fluent Builder API

Added discoverable builder methods:

  • DeleteItemEnhancedRequest.Builder#withOptimisticLocking(...)
  • TransactDeleteItemEnhancedRequest.Builder#withOptimisticLocking(...)

Example:

DeleteItemEnhancedRequest request = DeleteItemEnhancedRequest.builder()
    .key(itemKey)
    .withOptimisticLocking(versionValue, "version")
    .build();

table.deleteItem(request);

3. Centralized Helper: OptimisticLockingHelper

A new @SdkPublicApi class that:

  • Builds the version condition expression:
    <versionAttributeName> = :version_value
  • Merges version conditions with existing conditions using AND
  • Applies locking only when:
    • useOptimisticLocking == true
    • The table schema contains a version attribute
    • The provided item has a non-null version value

If any of these conditions are not met, the delete proceeds unconditionally.


Modifications

  • Added new overload deleteItem(T keyItem, boolean useOptimisticLocking) (Sync & Async)
  • Deprecated implicit deleteItem(T keyItem) methods
  • Added .withOptimisticLocking(...) to request builders
  • Introduced OptimisticLockingHelper
  • Implemented safe condition merging logic
  • Added unit and integration tests
  • Ensured compatibility with VersionedRecordExtension
  • Preserved existing API contracts

Testing

Includes:

  • Unit tests for condition generation and merging
  • Integration tests for sync and async tables
  • Transactional delete validation
  • Version match success scenarios
  • Version mismatch failure scenarios
  • Backward compatibility verification

All new and existing tests pass successfully.

Test Coverage on modified classes:

image

Test Coverage Checklist

Scenario Done Comments if Not Done
1. Different TableSchema Creation Methods
a. TableSchema.fromBean(Customer.class) [x]
b. TableSchema.fromImmutableClass(Customer.class) for immutable classes [x]
c. TableSchema.documentSchemaBuilder().build() [ ]
d. StaticTableSchema.builder(Customer.class) [x]
2. Nesting of Different TableSchema Types
a. @DynamoDbBean with annotated auto-generated key []
b. @DynamoDbImmutable with annotated auto-generated key []
c. Auto-generated key combined with partition/sort key []
3. CRUD Operations
a. scan() [ ]
b. query() [x]
c. updateItem() preserves existing value or generates when absent [x]
d. putItem() with no key set (auto-generation occurs) [x]
e. putItem() with key set manually [x]
f. getItem() retrieves auto-generated key [x]
g. deleteItem() [x]
h. batchGetItem() [ ]
i. batchWriteItem() [x]
j. transactGetItems() [ ]
k. transactWriteItems() [x]
4. Data Types and Null Handling
a. Annotated attribute is null → key auto-generated []
b. Annotated attribute non-null → value preserved []
c. Validation rejects non-String annotated attribute []
5. AsyncTable and SyncTable
a. DynamoDbAsyncTable Testing [x]
b. DynamoDbTable Testing [x]
6. New/Modification in Extensions
a. Works with other extensions like VersionedRecordExtension [x]
b. Test with Default Values in Annotations [ ]
c. Combination of Annotation and Builder passes extension [ ]
7. New/Modification in Converters
a. Tables with Scenario in ScenarioSl No.1 (All table schemas are Must) [ ]
b. Test with Default Values in Annotations [ ]
c. Test All Scenarios from 1 to 5 [ ]

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@anasatirbasa anasatirbasa force-pushed the poc/optimistic-locking-for-delete-operations branch from 5a10899 to 515b581 Compare December 12, 2025 12:51
@anasatirbasa anasatirbasa force-pushed the poc/optimistic-locking-for-delete-operations branch from 30f646c to 927aacb Compare January 12, 2026 16:54
@anasatirbasa anasatirbasa force-pushed the poc/optimistic-locking-for-delete-operations branch from 1494faa to a7a2356 Compare January 20, 2026 10:23
@anasatirbasa anasatirbasa force-pushed the poc/optimistic-locking-for-delete-operations branch from 80e81ed to a1f9cfd Compare February 20, 2026 17:36
@anasatirbasa anasatirbasa deleted the poc/optimistic-locking-for-delete-operations branch February 20, 2026 17:44
@anasatirbasa anasatirbasa restored the poc/optimistic-locking-for-delete-operations branch February 20, 2026 17:46
@anasatirbasa anasatirbasa reopened this Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant