Skip to content

Conversation

@emil2k
Copy link
Contributor

@emil2k emil2k commented Jan 31, 2018

- What I did
Enabled content encoding negotiation to speed up retrieval of container archives.

A better solution might be, some sort of middleware applied to most endpoints on the server and from the client side an Accept-Encoding header could be set either using a client's customHTTPHeaders attribute or in individual methods.

I'm not really sure this is the best way to do this, but I'm posting this here to get feedback and guidance.

- How I did it
Parses the Accept-Encoding header in handler for GET /containers/{id}/archive requests, determines the best encoding, compresses the files, and adds the appropriate Content-Encoding header.

- How to verify it
I'm not sure how to add a test for this, looking for feedback.

- Description for the changelog
Content encoding negotiation added to archive request.

@emil2k emil2k requested a review from dnephin as a code owner January 31, 2018 13:19
@emil2k emil2k force-pushed the gzip-archive branch 6 times, most recently from 091e283 to 59b9e7e Compare January 31, 2018 15:29
@dnephin
Copy link
Member

dnephin commented Jan 31, 2018

hmm, it looks like our vendor check is broken. I believe github.com/golang/gddo was added as a new dependency but not added to vendor.conf. vendor should have failed because of this.

Copy link
Member

@dnephin dnephin left a comment

Choose a reason for hiding this comment

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

The new dependency needs to be added to vendor.conf I will look into why it didn't fail.

The approach seems reasonable to me. A middleware might be too much because it's not necessarily safe for all cases, but moving it out to a function should at least let us re-use it.

Copy link
Member

Choose a reason for hiding this comment

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

This suggests that maybe the content-type should change as well?

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 since the Content-Encoding header is being set to gzip the Content-Type should stay as application/x-tar as it is the underlying content type after decoding:

The Content-Encoding entity header is used to compress the media-type. When present, its value indicates which encodings were applied to the entity-body. It lets the client know, how to decode in order to obtain the media-type referenced by the Content-Type header.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding

Copy link
Member

Choose a reason for hiding this comment

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

I think this code should go into a function so that we'll be able to re-use it later.

func writeCompressedResponse(r *http.Request,  w http.ResponseWriter, body io.Reader) error {
...
}

Copy link
Member

Choose a reason for hiding this comment

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

Interesting!

We have ioutils.ReadCloserWrapper from github.com/docker/docker/pkg/ioutils which does this as well without the anonymous struct. I think it would be good to use that.

Is it really safe to defer gr.Close() here? Doesn't that close the Reader before it's used? I think you would need to use a closer on ioutils.ReadCloserWrapper that closes both Readers.

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 on the closer. I need to setup some stuff to develop on the server side, so I hadn't really tested this.

Copy link
Member

Choose a reason for hiding this comment

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

should also be a new function readResponsebody(resp serverResponse) (io.ReadCloser, error).

@dnephin dnephin mentioned this pull request Feb 2, 2018
@emil2k emil2k force-pushed the gzip-archive branch 3 times, most recently from 2440772 to 394116d Compare February 5, 2018 12:54
@emil2k
Copy link
Contributor Author

emil2k commented Feb 5, 2018

@dnephin I made some fixes as you suggested.

On the client side, as long as the http.Transport's DisableCompression field is set to false there is no need to manually set Accept-Encoding and then decode based on the Content-Encoding header so all I did was set DisableCompression explicitly to false in the client constructors.

Copy link
Member

@dnephin dnephin left a comment

Choose a reason for hiding this comment

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

Looks good.

I think it could use a test for writeCompressedResponse(), but feel free to wait until someone else has reviewed the design

client/client.go Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Nice find! I didn't know about this

@emil2k
Copy link
Contributor Author

emil2k commented Feb 14, 2018

Resolved conflicts and rebased this on master.

Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

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

LGTM 🐸
Should we split the vendoring to the code in two separate commits ? 👼

@emil2k
Copy link
Contributor Author

emil2k commented Feb 16, 2018

@vdemeester It is up to you guys, I have no preference on splitting up the commit.

@thaJeztah
Copy link
Member

Given that this was opened to improve performance, do we need bench tests for this?

Silly question; is the compression done "streaming" or is the content read into memory first?

@thaJeztah
Copy link
Member

ping @unclejack @cpuguy83 PTAL

@emil2k
Copy link
Contributor Author

emil2k commented Feb 19, 2018

Given that this was opened to improve performance, do we need bench tests for this?

I'm not sure benchmarking is necessary in this case, because it would simply be testing the compression rate which would depend on the particular data chosen for the benchmark.

Silly question; is the compression done "streaming" or is the content read into memory first?

The data is being compressed in as a stream as it is written to the client.

@emil2k
Copy link
Contributor Author

emil2k commented Feb 22, 2018

Rebased it on master to resolve conflicts.

client/client.go Outdated
Copy link
Member

Choose a reason for hiding this comment

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

This should be the default, so not needed

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 specified it to be explicit that the proper behavior of the client depends on that property value.

Also, if for whatever reason the DisableCompression field is removed or renamed the build would break and then things could be corrected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's up to you though, do you want me to remove the setting?

Copy link
Contributor

Choose a reason for hiding this comment

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

if for whatever reason the DisableCompression field is removed or renamed

I regard the Go team highly enough that I'm confident that would never happen. I think it's safe to remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I have removed this setting and rebased on master.

client/client.go Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@tiborvass
Copy link
Contributor

LGTM

@codecov
Copy link

codecov bot commented Feb 24, 2018

Codecov Report

Merging #36164 into master will increase coverage by <.01%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master   #36164      +/-   ##
==========================================
+ Coverage   34.64%   34.65%   +<.01%     
==========================================
  Files         612      612              
  Lines       45310    45310              
==========================================
+ Hits        15696    15700       +4     
+ Misses      27556    27553       -3     
+ Partials     2058     2057       -1

Signed-off-by: Emil Davtyan <emil2k@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants