Added request body buffer regeneration#43
Added request body buffer regeneration#43dylandreimerink wants to merge 8 commits intoopenresty:masterfrom
Conversation
lib/resty/upload.lua
Outdated
| end | ||
|
|
||
| local function finish_body(self) | ||
| if self.resore_body then |
lib/resty/upload.lua
Outdated
| sock = sock, | ||
| size = chunk_size or CHUNK_SIZE, | ||
| line_size = max_line_size or MAX_LINE_SIZE, | ||
| resore_body = restore_body_buffer or false, |
There was a problem hiding this comment.
resore -> restore? Also or false not needed, though, doesn't hurt much either.
lib/resty/upload.lua
Outdated
|
|
||
| local data = sock:receive(2) | ||
| if data == "--" then | ||
| append_body(self, "\r\n--" .. self.boundary .. "--\r\n") |
There was a problem hiding this comment.
We always concatenate strings here. Even when restore_body is false. Same thing happens in other append_body places. Maybe just checking the boolean variable doesn't warrant its own function and that can be inlined. Then we also solve this issue.
lib/resty/upload.lua
Outdated
|
|
||
| local line, err = read_line(self.line_size) | ||
| if not line then | ||
| finish_body(self); |
|
I fixed the typo and implemented you suggestion. I am not sure though if it is faster to append multiple times like I have done now or to create a new string and append once. |
|
Yes, previously you created strings even when not appending anything. |
lib/resty/upload.lua
Outdated
| return sock:settimeout(timeout) | ||
| end | ||
|
|
||
| local function append_body(self, ...) |
There was a problem hiding this comment.
I don't think you need to use varargs here, as you only ever have at most 3 args. Also you don't need to create a table with varargs, you can select("#", ...) and select(1, ...).
|
@dylandreimerink thanks for working on this. I think that one thing to add is test(s). |
|
I took a look at the source code for ngx.req.append_body which is quite big and does a memcpy. So I think it is best to ditch the whole idea of a separate function ( like u suggested before ) and concatenate a single string in the main functions. Then calling ngx.req.append_body once right before ngx.req.finish_body to minimize overhead. I will work on that as soon as I have time |
|
This should do it. I replaced the appending by a string buffer which should make it more performant. If this passes the only thing left to do is to make tests. I have to admit however that I do not yet understand how this unit test framework works, so i may need a little bit of guidance. |
|
I am not sure what does it add to buffer to Lua table? Just more complexity. For real string buffer we need something like this: LuaJIT/LuaJIT#14 I think that just |
|
Working from the assumption that append_body is relatively speaking slow since it has to copy data from the lua vm to nginx the idea is to keep the data in lua for as long as possible. Since lua strings are immutable they have to be recreated and copied every time you want to concatenate to an existing string. The solution would be to have a native implementation of a mutable string or string buffer. But since I have little hope for that in the near future I think the use of a table to store a list of strings and concatenating them once is the best option. The reason I am going to these lengths is because I will be using this feature in a proxy with a high throughput, so for me personally speed and optimization is quite important. So in light of that I will benchmark the different solutions so we can make an informed decision instead of having to work based on assumptions. |
|
I made the benchmark. The results are to me a bit unexpected. I tested 4 variations and the original, the summarized results are as follows:
The variation without the string buffer is the fastest but the difference is almost negligible. |
|
@bungle Have you had time to look at the last changes? |
There was a problem hiding this comment.
I left some more comments. Mostly style related changes. Biggest pressing issue right now is that this doesn't yet have tests. I think we should have good test suite that also tests with invalid input. Should we actually have some kind of internal error handler here that runs in case of error happens, and then just writes rest of the buffer back, e.g. leaving the body intact.
| if not read_line then | ||
|
|
||
| if restore_body_buffer then | ||
| ngx_finish_body() |
There was a problem hiding this comment.
The previous read, on line 72, was successful, but we didn't write the request body back, is this intended? Maybe there are many similar cases in code, but no easy way to solve? E.g. on errors we don't write the request body back.
There was a problem hiding this comment.
The sock:receiveuntil returns an iterator Lua function and doesn't actually read data from the buffer so there is noting to restore.
| end | ||
|
|
||
| if self.restore_body_buffer then | ||
| ngx_append_body(line .. "\r\n") |
There was a problem hiding this comment.
I think this is fine, but you could also have:
ngx_append_body(line)
ngx_append_body("\r\n")There was a problem hiding this comment.
I don't see any point in not concatenating the string here, the same goes for the rest of the remarks regarding concatenation.
| local data = sock:receive(2) | ||
| if data == "--" then | ||
| if self.restore_body_buffer then | ||
| ngx_append_body("\r\n--" .. self.boundary .. "--\r\n") |
There was a problem hiding this comment.
Same here:
ngx_append_body("\r\n--")
ngx_append_body(self.boundary)
ngx_append_body(ngx_append_body("--\r\n"))Not a big deal.
| end | ||
|
|
||
| if self.restore_body_buffer then | ||
| ngx_append_body("\r\n--" .. self.boundary .. "\r\n") |
There was a problem hiding this comment.
This coud be cached before the while loop:
local boundary_delimiter = "\r\n--" .. self.boundary .. "\r\n"And then here:
ngx_append_body(boundary_delimiter)There was a problem hiding this comment.
There is no while loop surrounding this line
| local preamble = read2boundary(size) | ||
| if not preamble then | ||
| if self.restore_body_buffer then | ||
| ngx_append_body("--" .. self.boundary) |
There was a problem hiding this comment.
Ditto here:
ngx_append_body("--")
ngx_append_body(self.boundary)Yes, bikeshedding :-).
| if dummy then | ||
| if self.restore_body_buffer then | ||
| ngx_finish_body() | ||
| end |
| if err then | ||
| if self.restore_body_buffer then | ||
| ngx_finish_body() | ||
| end |
| if err and err ~= 'closed' then | ||
| if self.restore_body_buffer then | ||
| ngx_finish_body() | ||
| end |
| if err then | ||
| if self.restore_body_buffer then | ||
| ngx_finish_body() | ||
| end |
| if err then | ||
| if self.restore_body_buffer then | ||
| ngx_finish_body() | ||
| end |
I made a fix for issue #41 and #42.
Optional support for body buffer regeneration.