Fix httpfs deadlock if there is a s3 region redirect#335
Conversation
|
@carlopi I think the CI failure is a flake |
|
@carlopi can we merge this? |
|
@NiclasHaderer - we'll get back to you here shortly! |
dentiny
left a comment
There was a problem hiding this comment.
Thanks for the fix!
This PR actually contains two orthogonal changes: deadlock fixing and region retry, I'm wondering if we could split it into two PRs? The former is a bug fix, the later is an enhancement.
Bugfix part LGTM
|
BTW, just share some my idea here:
Pseudocode void FullDownload() {
try {
} catch (...) {
cached_file_handle.ResetBuffer(); // under lock
cached_file_handle.reset(); // release lock
throw;
}
} |
|
Thanks for the feedback. Implemented your requested changes. I'd prefer to not split the PR if its OK with you. I'm currently super busy and the PR is not super huge. Is that OK with you? |
dentiny
left a comment
There was a problem hiding this comment.
Overall LGTM, could you please add doc for the region redirect logic? Either in the code or in the PR description.
| if (it == 0 && result->HasHeader("x-amz-bucket-region")) { | ||
| if (it == 0 && TryGetUpdatedBucketRegion(s3_auth_params, *result, updated_bucket_region)) { | ||
| // bucket region was updated below | ||
| } else if (!result->HasHeader("x-amz-bucket-region")) { |
There was a problem hiding this comment.
The constant has appeared for multiple times in the code change, let's make it a constant variable and add comment.
| auto result = make_request(); | ||
| string updated_bucket_region; | ||
| if (TryGetUpdatedBucketRegion(s3_handle.auth_params, *result, updated_bucket_region)) { | ||
| s3_handle.ResetDownloadState(); |
There was a problem hiding this comment.
I'm wondering if we could add a WARNING level logging?
Cherry-pick #335 deadlock change
|
Hi @NiclasHaderer , we're investigating a deadlock issue which could be related to your fix, since I didn't see this PR getting updated for two weeks, I copy part of your change in this PR to #363. |
|
I did all you asked for and added docs in the or description, so as far as I'm concerned this can be merged |
Thanks for the reply! So |
The deadlock happens when calling
S3FileHandle::Initializeandforce_downloadset to true.S3FileHandle::Intializewith aFileOpenerwhich in turn calls theHTTPFileHandle::Initialize. TheFileOpeneris only used to retrive theClientContextand theHTTPState. The HTTPState contains references to all cached files for thisClientContext.HTTPFileHandle::Initializewe get a reference to thisCachedFile. ThatCachedFileis then resolved to aCachedFileHandlewhich locks theCachedFile. As long as theCachedFileHandleis alive and theCachedFileHandlehas not been initialized theCachedFileis locked and no newCachedFileHandlecan be created. TheCachedFileHandleis now stored in theHTTPFileHandlewhich in turn is extended by theS3FileHandle.HTTPFileHandle::Initializefails (because we have been redirected and 301!=200)S3FileHandle::Intializeretries the initialization usingHTTPFileHandle::Initializewith a different S3 region. For this retry theCachedFileHandlesays alive, because itHTTPFileHandlewhich owns it is still alive.HTTPFileHandle::Initializewe have the problem that theCachedFileHandleis still holding the lock forCachedFile, butHTTPFileHandle::Initializestull tries to create a newCachedFileHandle. This is not possible because the already existingCachedFileHandlestill holds the lock onCachedFile.This PR fixes this by releasing the lock the
CachedFileHandleholds if we fail to read from S3. Additionally it implements the region retry mechanism for more S3 call paths.