Skip to content
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

Fix infinite loop if Reader returns io.ErrUnexpectedEOF #620

Merged
merged 1 commit into from
Apr 12, 2016

Conversation

ncw
Copy link
Contributor

@ncw ncw commented Apr 7, 2016

Apparently some HTTP transactions can return io.ErrUnexpectedEOF, eg
https://groups.google.com/forum/#!topic/golang-nuts/2wDPB42-rZ0

Before this change, this would result in S3Manager sending a lot of 0
sized parts, eventually causing the error "TotalPartsExceeded:
exceeded total allowed configured MaxUploadParts".

@@ -508,6 +508,7 @@ func (u *multiuploader) upload(firstBuf io.ReadSeeker) (*UploadOutput, error) {

// Read and queue the rest of the parts
for u.geterr() == nil {
num++
Copy link
Contributor

Choose a reason for hiding this comment

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

Why was this moved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What happens is that after the change it does one less iteration of the loop exiting at the first io.ErrUnexpectedEOF instead of iterating again and exiting at the io.EOF.

I moved it to make the unit tests pass!

Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't this always cause one less iteration? It may be best to update the unit tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My reading of the code is that it is correct now.

num starts on 1, because one part gets sent before the loop starts.

Say MaxUploadParts is 2.

First time around the loop num gets incremented to 2 before the check against MaxUploadParts.

The num > MaxUploadParts check succeeds and we send that part (the second).

Second time around the loop num gets incremented to 3 - the check fails and the loop is aborted before sending the 3rd part.

The test that fails without this change is TestUploadOrderMultiBufferedReaderExceedTotalParts. Looking at that code I think that is correct.

It worked before because the loop did one extra iteration it shouldn't have done.

I could be wrong though so a second opinion would be good!

Copy link
Contributor

Choose a reason for hiding this comment

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

The previous change would increment to 3 and then break on an io.EOF since there are no more parts. In this case it would start at 1, increment to 2 and upload the next part with no errors. Finally, increment to three and set the err to the excess error, but we want to break on an io.EOF and have nothing set to the error. Does that sound right? Let me know if I am missing something

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think before my change it sent one part too many

  • send first part outside loop
  • num = 1
  • if num > MaxUploadParts -> no
  • num++ (2)
  • send second part
  • if num > MaxUploadParts -> no
  • num++ (3)
  • send third part
  • if num > MaxUploadParts -> yes, break

Copy link
Contributor

Choose a reason for hiding this comment

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

  • send first part outside loop
  • num = 1
  • if num > MaxUploadParts -> no
  • num++ (2)
  • send second part
  • if num > MaxUploadParts -> no
  • num++ (3)
  • nextReader() return err
  • err is io.EOF
  • break

Lemme see what that unit test is doing

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, nvm. Drew it out. I see what you are saying. Can you add one more unit test to test for EOF?

@xibz
Copy link
Contributor

xibz commented Apr 7, 2016

Hello @ncw, thank you for taking the time to put this PR together. I am going to reach out to S3 and see when an io.ErrUnexpectedEOF would occur and how they want that handled. Also, what are you doing to produce this error?

@ncw
Copy link
Contributor Author

ncw commented Apr 7, 2016

I haven't observed this directly, but a user of my rclone program reported the problem and we debugged it together. See rclone/rclone#415

I think this error is very unlikely to occur normally, however my user could make it happen reliably with their ceph cluster.

According to the thread I linked ErrUnexpectedEOF can happen when using https.

I've tested the patch as has my user with the problem and it passes the unit tests, though travis seems to be broken at the moment (probably because of this https://groups.google.com/forum/#!topic/golang-announce/JMs4_CGbXWk)

@xibz
Copy link
Contributor

xibz commented Apr 7, 2016

@ncw - Okay, I'll forward this to S3.
Yea, cmd/vet was deleted from tools today.

@xibz
Copy link
Contributor

xibz commented Apr 7, 2016

@ncw - Fixed travis. If you could resync with master, that'd be great!

@xibz
Copy link
Contributor

xibz commented Apr 7, 2016

@ncw - Okay, your changes make sense. Once you add the other unit test and sync with master I can merge it in

Apparently some HTTP transactions can return io.ErrUnexpectedEOF, eg
https://groups.google.com/forum/#!topic/golang-nuts/2wDPB42-rZ0

Before this change, this would result in S3Manager sending a lot of 0
sized parts, eventually causing the error "TotalPartsExceeded:
exceeded total allowed configured MaxUploadParts".
@ncw ncw force-pushed the fix-unexpected-eof branch from b20d2b7 to 1411945 Compare April 12, 2016 16:57
@ncw
Copy link
Contributor Author

ncw commented Apr 12, 2016

I've updated and rebased the PR - let me know what you think!

Thanks

Nick

@xibz
Copy link
Contributor

xibz commented Apr 12, 2016

@ncw - Awesome! Thanks for the update! The changes look good.

@xibz xibz merged commit c877804 into aws:master Apr 12, 2016
xibz added a commit that referenced this pull request Apr 19, 2016
skotambkar added a commit to skotambkar/aws-sdk-go that referenced this pull request May 20, 2021
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