Skip to content

S3CrossRegion Sync and Async Clients Redirect implementation #4089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

joviegas
Copy link
Contributor

@joviegas joviegas commented Jun 9, 2023

Motivation and Context

  • Implement redirection in S3CrossRegionSyncClient and S3CrossRegionAsyncClient
  • Perform a redirect whenever the first call fails with a redirect exception.
  • Pass the supplier to endPointProvider to retrieve the region from cache or headBucket call.

Modifications

  • The initial call is made using the default client.
  • If the call fails with a 301 status error, the region is extracted from the error response header.
  • The cache is updated, and the call is made by overriding the endpoint provider.
  • The overridden endpoint provider checks the cache to obtain the region.
  • If the region is not updated in the cache, a HeadBucket call is made to retrieve and update the region.

Testing

  • Junits added

License

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

@joviegas joviegas requested a review from a team as a code owner June 9, 2023 23:31
Copy link
Contributor

@cenedhryn cenedhryn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Failed codegen test should be fixed by PR #4080

@joviegas joviegas changed the title S3CrossRegionSyncClient Redirect implementation S3CrossRegion Sync and Async Clients Redirect implementation Jun 14, 2023
@joviegas joviegas force-pushed the joviegas/cross_region_decorator_sync_implementation branch from 73f1003 to 233b93e Compare June 14, 2023 02:14

return operation.apply(requestWithDecoratedEndpointProvider(request, bucket.get()))
.whenComplete((r, t) -> handleOperationFailure(t, bucket.get()));
if (bucketToRegionCache.containsKey(bucketName)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the sync case, the try-catch contains both the call with cache hit and the cache miss, so the catch covers both cases. In this async instance, we will not catch a potential redirect as a result of calling with a cached region and we won't clear the cache?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line number 66 clears the cache.
Note that HeadBucket fall back logic comes into picture only when first fall back fails to get region and in this case we clear the cache.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant the code within the if-statement if (bucketToRegionCache.containsKey(bucketName)). No other code will execute below that. If the call to requestWithDecoratedEndpointProvider gets a redirect, it will not be handled. So the sync and async code will have slightly different behavior in that edge case. Question is if it's likely to occur at all and therefore worth handling - i.e., you get a region from the cache but it's the wrong region. Probably not a huge risk.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch !! This can happen if the bucket is changed, thanks for catching this bug.
Will update the code and add a test case for below standalone API call scenarios

  1. Redirect Cached and Success ==> 1st call
  2. Success ==> 2nd call
  3. Redirect and success ==> 3 rd Call


@SdkInternalApi
public final class S3CrossRegionAsyncClient extends DelegatingS3AsyncClient {

private final Map<String, CompletableFuture<Region>> bucketToRegionCache = new ConcurrentHashMap<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use LruCache to prevent this map from growing unbounded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LruCache cache doenot provide API to modify the Cache it just caches the content and provides get.
I will create a separate PR to make this bounded cache

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can update LruCache to support this? @cenedhryn WDYT?

Copy link
Contributor

@cenedhryn cenedhryn Jun 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems most use cases for Lru can be solved with a LinkedHashMap. (It may make sense to rewrite our LruCache on that model, but that's a different question)

For instance:

    private static final int CAPACITY = 100;

    private final Map<String, Region> bucketToRegionCache = Collections.synchronizedMap(
        new LinkedHashMap<String, Region>(CAPACITY) {
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > CAPACITY;
            }
        });

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we cannot implement using ConcurrentHashMap since it internally just does a putAlll and doesnot actually use LinkedHashMap in above

@joviegas joviegas force-pushed the joviegas/cross_region_decorator_sync_implementation branch from ff52a5f to d086ece Compare June 19, 2023 14:47
String bucketName,
CompletableFuture<ReturnT> returnFuture) {

// // TODO: will fix the casts with separate PR
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a @SuppressWarnings("unchecked") statement to requestWithDecoratedEndpointProvider in CrossRegionUtils in that PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done ...Was wondering if there is a tool/scan which suggest this automatically ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually notice because IntelliJ gets angry and makes lines yellow.

@joviegas joviegas force-pushed the joviegas/cross_region_decorator_sync_implementation branch from a54eabc to f99d959 Compare June 20, 2023 20:18
@sonarqubecloud
Copy link

SonarCloud Quality Gate failed.    Quality Gate failed

Bug C 5 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 74 Code Smells

89.7% 89.7% Coverage
0.1% 0.1% Duplication

idea Catch issues before they fail your Quality Gate with our IDE extension sonarlint SonarLint

@joviegas joviegas merged commit 5d57416 into cross_region_bucket_access/project_branch Jun 21, 2023
joviegas added a commit that referenced this pull request Jul 5, 2023
* Adding a generic method invokeOperation for abstract delegating clien… (#3996)

Adding a generic method invokeOperation for abstract delegating client to allow overriding behavior changes for all operations

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration (#3978)

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration

* updated review comments 1

* updated review comments 2

* Adds S3CrossRegion clients and codegen for retrieving bucket name (#4008)

* Adds S3CrossRegion clients and codegen for retrieving bucket name

* Removes codegen of bucket parameter since getValueForField() is better

* Add back overloads

* Adds cross region client logic for decorating endpoint provider (#4026)

* Adds cross region client logic for decorating endpoint provider

* Paginated methods returning publisher or iterable implement logic in … (#4046)

* Paginated methods returning publisher or iterable implement logic in interface instead of throwing unsupported exception

* Added internal annotation to class

* Wraps s3 client in cross regional client when enabled (#4080)

* Wraps s3 client in cross regional client when enabled

* Adds composer interface

* Add User Agent Api name for Cross region API calls (#4105)

* Add User Agent Api name for Cross region API calls

* Added test case for default client not to have user agent related to cross region

* S3CrossRegion Sync and Async Clients Redirect implementation (#4089)

* S3CrossRegionSyncClient Redirect implementation

* Added implementation for Async client Decorator

* Updated older Cross region test cases

* Added paramterized test

* Async Exception checged to completableException

* Updated test cases and changes the Exception handling when HeadBucket Call fails

* Handled Anna-karin's comments

* Removed async execution of HeadBucket and attached it to the completableFuture of main request

* Handled Zoe's comments

* Added test case when Redirected after the Region is cached

* Changed region constant to Region Type in Tests

* Cross region support for CRT Client (#4129)

* Cross region support for CRT Client

* removing common class

* handled review comments

* Integration test cases for Cross region Async and Sync Clients (#4128)

* Integration test cases for Cross region Sync and Sync Clients

* Renamed files as Integration test

* Handled CR comments to take care of retries thus captureInterceptor is removed

* rebased and added CRT in Integ test

* removed sout from integ

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators (#4151)

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators

* Removed from S3Configurations

* Move the optional parameter in getter

---------

Co-authored-by: Anna-Karin Salander <[email protected]>
L-Applin pushed a commit that referenced this pull request Jul 24, 2023
* Adding a generic method invokeOperation for abstract delegating clien… (#3996)

Adding a generic method invokeOperation for abstract delegating client to allow overriding behavior changes for all operations

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration (#3978)

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration

* updated review comments 1

* updated review comments 2

* Adds S3CrossRegion clients and codegen for retrieving bucket name (#4008)

* Adds S3CrossRegion clients and codegen for retrieving bucket name

* Removes codegen of bucket parameter since getValueForField() is better

* Add back overloads

* Adds cross region client logic for decorating endpoint provider (#4026)

* Adds cross region client logic for decorating endpoint provider

* Paginated methods returning publisher or iterable implement logic in … (#4046)

* Paginated methods returning publisher or iterable implement logic in interface instead of throwing unsupported exception

* Added internal annotation to class

* Wraps s3 client in cross regional client when enabled (#4080)

* Wraps s3 client in cross regional client when enabled

* Adds composer interface

* Add User Agent Api name for Cross region API calls (#4105)

* Add User Agent Api name for Cross region API calls

* Added test case for default client not to have user agent related to cross region

* S3CrossRegion Sync and Async Clients Redirect implementation (#4089)

* S3CrossRegionSyncClient Redirect implementation

* Added implementation for Async client Decorator

* Updated older Cross region test cases

* Added paramterized test

* Async Exception checged to completableException

* Updated test cases and changes the Exception handling when HeadBucket Call fails

* Handled Anna-karin's comments

* Removed async execution of HeadBucket and attached it to the completableFuture of main request

* Handled Zoe's comments

* Added test case when Redirected after the Region is cached

* Changed region constant to Region Type in Tests

* Cross region support for CRT Client (#4129)

* Cross region support for CRT Client

* removing common class

* handled review comments

* Integration test cases for Cross region Async and Sync Clients (#4128)

* Integration test cases for Cross region Sync and Sync Clients

* Renamed files as Integration test

* Handled CR comments to take care of retries thus captureInterceptor is removed

* rebased and added CRT in Integ test

* removed sout from integ

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators (#4151)

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators

* Removed from S3Configurations

* Move the optional parameter in getter

---------

Co-authored-by: Anna-Karin Salander <[email protected]>
L-Applin pushed a commit that referenced this pull request Jul 24, 2023
* Adding a generic method invokeOperation for abstract delegating clien… (#3996)

Adding a generic method invokeOperation for abstract delegating client to allow overriding behavior changes for all operations

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration (#3978)

* Add endpointProvider in ClientConfig and RequestOverrideConfig. Also add crossRegionBucketAccess in S3Configuration

* updated review comments 1

* updated review comments 2

* Adds S3CrossRegion clients and codegen for retrieving bucket name (#4008)

* Adds S3CrossRegion clients and codegen for retrieving bucket name

* Removes codegen of bucket parameter since getValueForField() is better

* Add back overloads

* Adds cross region client logic for decorating endpoint provider (#4026)

* Adds cross region client logic for decorating endpoint provider

* Paginated methods returning publisher or iterable implement logic in … (#4046)

* Paginated methods returning publisher or iterable implement logic in interface instead of throwing unsupported exception

* Added internal annotation to class

* Wraps s3 client in cross regional client when enabled (#4080)

* Wraps s3 client in cross regional client when enabled

* Adds composer interface

* Add User Agent Api name for Cross region API calls (#4105)

* Add User Agent Api name for Cross region API calls

* Added test case for default client not to have user agent related to cross region

* S3CrossRegion Sync and Async Clients Redirect implementation (#4089)

* S3CrossRegionSyncClient Redirect implementation

* Added implementation for Async client Decorator

* Updated older Cross region test cases

* Added paramterized test

* Async Exception checged to completableException

* Updated test cases and changes the Exception handling when HeadBucket Call fails

* Handled Anna-karin's comments

* Removed async execution of HeadBucket and attached it to the completableFuture of main request

* Handled Zoe's comments

* Added test case when Redirected after the Region is cached

* Changed region constant to Region Type in Tests

* Cross region support for CRT Client (#4129)

* Cross region support for CRT Client

* removing common class

* handled review comments

* Integration test cases for Cross region Async and Sync Clients (#4128)

* Integration test cases for Cross region Sync and Sync Clients

* Renamed files as Integration test

* Handled CR comments to take care of retries thus captureInterceptor is removed

* rebased and added CRT in Integ test

* removed sout from integ

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators (#4151)

* Attach crossRegionAccessEnabled as CustomClientParams to a client Builder, also mention of Composers are renamed as decorators

* Removed from S3Configurations

* Move the optional parameter in getter

---------

Co-authored-by: Anna-Karin Salander <[email protected]>
@joviegas joviegas deleted the joviegas/cross_region_decorator_sync_implementation branch August 30, 2023 22:58
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.

3 participants