-
Notifications
You must be signed in to change notification settings - Fork 381
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
Send VFP_END with last data for v1f chunked & read ahead #3809
base: master
Are you sure you want to change the base?
Conversation
With varnishcache#3809 in place, we can now differentiate properly between the cache size being exactly right and too small.
ec5c816
to
cda5b46
Compare
With varnishcache#3809 in place, we can now differentiate properly between the cache size being exactly right and too small.
We should only attempt to read the next chunked header if we have read-ahead bytes. Blocking for the next chunked header will break some web-applications which rely on complete concurrent delivery of chunks. |
cda5b46
to
a4f0921
Compare
This is implemented with the last force-push as of 24b9776. Regarding the possible reduction of system calls, I would volunteer to do this next. I also restructered the commits and noticed another issue on the way: We accepted chunks without the chunk-end (CR)?LF. This is fixed in 4417928 |
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
9226b17
to
7c1160e
Compare
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
I have updated this PR with a readahead implementation for chunked encoding.
|
819a5df
to
3573c33
Compare
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
While this looks overall correct, it also complicates chunked parsing a great deal. Someone suggested (I think @bsdphk) that maybe it was time to have a receive buffer at the session level where we could always read up to the remaining buffer size and not be worried about cross-request boundaries. I suspect this would also simplify h2 parsing a great deal. |
3573c33
to
c9ce836
Compare
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
c9ce836
to
38c3499
Compare
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
Until now, we read the (CR)?LF at the end of a chunk as part of the next chunk header (see: /* Skip leading whitespace */). For a follow up commit, we are going to want to know if the next chunk header is available for read, so we now consume the chunk end as part of the chunk itself. This also fixes a corner case: We previously accepted chunks with a missing end-of-chunk (see fix of r01729.vtc). Ref: https://datatracker.ietf.org/doc/html/rfc7230#section-4.1
... which we are going to need in a follow up commit. No functional changes, diff best viewed with -b
While working on request body caching improvements, it was noticed that, for chunked encoding, we did not know the request body size before we attempted to read at least one additional byte because the chunked fetch did not return VFP_END with the last chunk, but rather only as a zero-length additional chunk. This commit changes chunked encoding processing to return VFP_END opportunistically if the next chunk header is available. Implementation: Unless there is pipeline readahead data available, the test for available data implies a poll(2) call. Relative to the existing cost of the current implementation, this cost is not considered relevant. To improve efficiency, we should consider a generic readahead for chunked encoding, probably by making the file descriptor non blocking and adding a readahead buffer.
It seems this test now shows no data loss more frequently, which I hope should be fine for the purpose of the test?
This commit contains only the init/fini mechanics for the state/buffer, it is not used yet. The state is allocated on the heap to be prepared for partial caching (see varnishcache#3798), where the V1F layer is left and control returns to VCL: - the worker workspace aws is not an option because it must be freed to its original state before returning to VCL. - the task (req) workspace is not an option because of rollbacks. While I would have preferred to avoid a heap allocation, it will be payed off by the reduction of system calls in follow up commits.
This is to support optional readaheads: The first io vector is for read data which the caller absolutely needs, any other io vectors are for potential readahead. The readahead is not used yet, for now, all v1f_read() calls use the IOV() macro to just wrap the existing single buffer.
We maintain a readahead buffer, which gets filled whenever we parse chunk headers and read chunks. The implementation works at the V1F layer only. Because we currently have no way to return, from this layer, data to the HTC pipeline, we must take great care to never over-read the current request. The existing code treats the CR in the CRLF end sequence for chunked encoding as optional, which, in general, leads to a lower safe readahead than if we required CR. For reading chunks, the readahead case is quite trivial: After each chunk, at least one NL needs to follow, plus the last 0 bytes chunk header (0 + NL), plus at least one NL for the end of trailers, totaling to four bytes of safe readahead. In pratice, usually two bytes will be read ahead, the CRLF ending the chunk. For the final chunk, the safe readahead is too conservative to read all of the usual CRLF 0 CRLF CRLF sequence, but the four bytes readahead is sufficient to trigger reading the final zero chunk header, such that we will return VFP_END properly. For reading chunk headers, the minimal safe readahead assumption is for the shortest possible end chunk, 0 NL NL. We very conservatively update the readahead, such that we will usually process a chunk header with two reads.
38c3499
to
fdf390c
Compare
With varnishcache#3809 in place, VFP_END is now signalled opportunistically. Thus, if we see VFP_OK with a full buffer, we still need one extra read to ensure that it does not return VFP_END.
I doubt a generic receive buffer, while useful, would change this in any relevant way. We would still need to ensure that the number of bytes required by each parsing step are available. The only thing a generic receive buffer would improve is the readahead, which would not need to be restricted to the current body. |
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.
I found a minor suggestion during a second pass on the patch series.
I'm still thinking we may be taking this problem from the wrong end. The last couple commits in particular drastically increase in complexity despite attempts at containing it.
The chunked header parser in current master is not just incomplete because it may forget to complain about missing [CR]LF delimiters, it's also incapable of parsing a chunked extension (even if it's only to ignore them).
I think we should merge the patch series to the point where VFP_END
is sent with the last chunk (and squash the test case stabilization to avoid git-bisect surprises). The read-ahead part should be handled separately.
cll = strtoumax(buf, &q, 16); | ||
if (q == NULL || *q != '\0') | ||
return (VFP_Error(vc, "chunked header number syntax")); | ||
cl = (ssize_t)cll; | ||
if (cl < 0 || (uintmax_t)cl != cll) | ||
return (VFP_Error(vc, "bogusly large chunk size")); |
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.
VNUM_hex()
? I'm aware you didn't really touch this part, I simply noticed.
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.
no opinion. Why do we even have vnum_uint ()
and do not just use strtoumax()
?
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.
To optionally work with [b..e)
ranges, not just null-terminated strings.
I honestly do not see the complexity increase. Can you please point to one or two examples?
Good point, we should handle extensions, but I believe this topic is orthogonal to this PR and related work. Being at it, we should also double check if we properly handle trailers. I had made an attempt to get trailer support in ages ago with #2477, but even if we do not add that, we should still at least somehow handle trailers (ignore? error?).
WFM, any progress is welcome |
The last 3 commits.
Agreed.
Agreed, we should start with ignoring them. An error is what we already get today when we expect In a previous discussion we had discussed new An alternative could be to send |
Bugwash:
|
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.
I was having another look at #4035 and remembered that we have this one open, and now it has a merge conflict to solve.
Anyway, revisiting this I have a few comments:
- we can drop 870f16c (since Vip4: add $Restrict in vcc #3915)
- 870f16c...12e0619 still look good to me (modulus merge conflict)
- I'd leave the last 3 commits to be revisited after looking at moving trailers outside of the VFP
bin/varnishd/http1/cache_http1_vfp.c
Outdated
if (vfe->priv2 == -1) { | ||
vfps = v1f_chunked_hdr(vc, htc, &vfe->priv2); | ||
if (vfps != VFP_OK) | ||
return (vfps); | ||
} |
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 should introduce a macro for this magic -1
.
v1fcp = calloc(1, sz); | ||
AN(v1fcp); | ||
v1fcp->magic = V1F_CHUNKED_PRIV_MAGIC; |
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 could now use ALLOC_FLEX_OBJ()
here.
Following up here on the topic of trailer support, motivated by #4035 (comment) As a personal preface, I would like to add that this triggers some frustration on my end. take this iteratively and not involve VCL support on day 1 was exactly what I tried to do in #2477 and various other tickets. It irritates me that when I mention the feedback (pushback, if you will) which I received at the time from the same group of people now working on a new attempt, things seem to have changed and "not having a clear VCL concept" suddenly seems to be OK. So now that I got this off my chest, let's leave the past behind - I also want to have trailer support and I will be happy to get back to these old tickets and make progress. Also I do want to collaborate. How to we proceed here? Do we have any new suggestions on the table? |
I offer you my apologies if I contributed to your frustration on this specific topic. Until you brought it up, I didn't remember your former attempt at dealing with trailers. Here is where we stand right now, based on #3809 (review):
At this point, first milestone, we preserve HTTP/1 framing in the presence of trailers, but we effectively drop them. I believe @walid-git got this working already (he's doing most of the work, when I say "we" I mostly refer to him). What we are planning next:
This second milestone would allow us to see how well Varnish integrates with applications relying on trailers, with caveats such as the risk of breaking check sums when filters are involved, hence the initial experimental status. I believe this also becomes a good basis to discuss how to expose trailers to VCL. I will try to revisit #2477 and see what we may reconsider with our current plan. edit: I submitted prematurely because of ctrl+return keyboard accident. |
While working on request body caching improvements, it was noticed that, for chunked encoding, we do not know the request body size before we have attempted to read at least one additional byte because the chunked fetch did not return
VFP_END
with the last chunk, but rather only as a zero-length additional chunk.This commit changes chunked encoding processing to read the next chunk header before returning the last bytes of the previous chunk. This allows to return
VFP_END
properly.Test cases are adjusted accordingly.
Diff is best viewed with -b option