-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Don't force IOContext.READONCE for src file in RemoteDirectory's copyFrom #18450
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
base: main
Are you sure you want to change the base?
Don't force IOContext.READONCE for src file in RemoteDirectory's copyFrom #18450
Conversation
1ad097b to
a0f175e
Compare
|
❌ Gradle check result for a0f175e: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
a0f175e to
f4bc8ff
Compare
|
❌ Gradle check result for f4bc8ff: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
8a67d47 to
e70cc01
Compare
|
@sachinpkale -- I'd appreciate your eyes on this. I tweaked your fix from #17502 to go back to using READONCE for the segments file, which meant that I needed to disable async uploads for that file. I'm not sure if that has any performance implications for the s3-repository implementation, since it will end up synchronously uploading that one file. |
|
❌ Gradle check result for e70cc01: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
The copyFrom method opens a source IndexInput, a destination IndexOutput, and calls copyBytes on the output, passing the input. For a RemoteDirectory, the output may be the remote store, which may try to parallelize the copyBytes implementation by doing a multipart upload across multiple threads. Lucene's default copyFrom assumes the copyBytes always runs on the current thread, which means that it can use IOContext.READONCE when opening the source file. Since we can't guarantee that for RemoteDirectory, we must override the Lucene implementation to use the "true" IOContext. It would arguably be a good idea to force the IndexInput context to be IOContext.DEFAULT, but there is an invariant that assumes the SegmentInfos file is always read with IOContext.READONCE. That should generally be fine, since the SegmentInfos file should never trigger a multipart upload (since it's tiny). Signed-off-by: Michael Froh <[email protected]>
e70cc01 to
931edf9
Compare
|
❌ Gradle check result for 931edf9: FAILURE Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change? |
| ); | ||
| assertBusy(() -> assertEquals(0, refreshCountLatch.getCount())); | ||
| assertBusy(() -> assertEquals(1, successLatch.getCount())); | ||
| assertBusy(() -> assertEquals(0, successLatch.getCount())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vikasvb90 -- I think this was one of your tests. I don't entirely understand why my change caused the value to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the assertion below that uploads failed > 1 is failing as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| try { | ||
| deleteFile(dest); | ||
| } catch (IOException e) { | ||
| // Ignore the exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shall we log the exception, so that we know there could be some leftover file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The copyFrom method in Lucene normally swallows this with IOUtils.deleteFilesIgnoringExceptions.
Unfortunately, OpenSearch uses forbiddenApis to prevent use of Lucene's IOUtils.
vikasvb90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We actually don't parallelise copying bytes from a single IndexInput. Here's the code pointer. Two reasons
- IndexInput is a stateful object just like other InputStream impls and therefore, we can't read bytes from multiple positions in parallel in a singe stream.
- We need the ability to track each set of read bytes by a stream separately for us to be able to compute individual checksums.
The way we do it today is create a new IndexInput for each part of file upload using a supplier passed to RemoteTranserContainer and track it independently and then process all later for checksum verification.
Therefore, we may not need to parallelise within a single IndexInput.
|
Thanks @vikasvb90 ! That makes a lot of sense. It occurs to me that OCI also must not be trying to do a parallel multipart upload. As I was jumping back and forth between the OpenSearch code, the OCI repository code, and the OCI storage client code, I assumed we were going into this So, the remaining cause for the |
|
That said, @vikasvb90, @linuxpi, and @sachinpkale -- do you see any risks or significant downsides with using While some remote store implementations (S3, Azure, and GCS) happen to execute the PUT request on the same thread that invoked Maybe we should add a method to |
Yes, it looks like this is the only option to make multi-part upload work in this client with minimal set of changes. |
|
But I think a better approach for sequential reads would be to use the same thread. This is also how it was done in the legacy multi-part code in repository-s3 plugin here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@msfroh I tested the changes with oci repository plugin and the condition to have READONCE for segments doesn't work. We still are facing same WrongThreadExcpetion in case of put requests. I was able to run without errors when IOContext is DEFAULT.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, the whole fix doesnt works. Only if I pull the RemoteDirectory changes it works.
|
This PR is stalled because it has been open for 30 days with no activity. |
|
This PR is stalled because it has been open for 30 days with no activity. |
Description
The copyFrom method opens a source IndexInput, a destination IndexOutput, and calls copyBytes on the output, passing the input. For a RemoteDirectory, the output may be the remote store, which may try to parallelize the copyBytes implementation by doing a multipart upload across multiple threads.
Lucene's default copyFrom assumes the copyBytes always runs on the current thread, which means that it can use IOContext.READONCE when opening the source file. Since we can't guarantee that for RemoteDirectory, we must override the Lucene implementation to use the "true" IOContext.
It would arguably be a good idea to force the IndexInput context to be IOContext.DEFAULT, but there is an invariant that assumes the SegmentInfos file is always read with IOContext.READONCE. That should generally be fine, since the SegmentInfos file should never trigger a multipart upload (since it's tiny).
Related Issues
Resolves #15902
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.