Please see my comments below.
- Ostap
---
1.) sys_proxy reads data in one format (byte stream) but replies in another format (chunked), and also http_* methods now read data in one format and write in another. Would be great to unify it as this complexity already resulted in one error in the exec_thread(): responding with http_500() for direct communication with the client rather than via sys_proxy (a client expects the byte stream rather than a chunk).
2.) It was there before (as a TODO) but while reading the code I got an idea how to fix it. The problem is that a transaction is committed prior to writing the last data chunk to a client socket. The later this is performed the better, since there is a good chance that a client will be able to close the socket and the transaction would get cancelled. I think it is just a matter of moving tx_commit() after the http_term() in processor(), and then performing the following changes in the exec_thread:
- 128 /* HTTP 500 only if no data was sent to the client */
- 129 if (cnt == 0)
+ 129 if (pio->err && !cio->err)
130 status = http_500(cio);
3.) sys_proxy uses a magic number (18), would be nice to document it.
4.) too many braces in chunk_recv():
---
103 if ((sys_readn(io, &sz, sizeof(sz)) <= 0))
---
1) a new "chunked" network IO introduced not to expose the chunked data exchange requirement for the sys_proxy.
2) I've moved the tx_commit right after the http_200 response in order delay a commit little bit. I did not want to move it even further because of two reasons:
a) a successful response (http_200, http_chunk or http_term) indicates only a successful transfer to main bandicoot process and not to the client
b) waiting with the commit until the result is fully sent might introduce a long running transaction.
In case of the http_500 we need to check for the count in order not to sent 500 response when client received some data already.
3) fixed.
4) fixed.
1.) essentially we want to reuse the same socket associated with the processor across different client requests. Here is how I imagine this: a socket reuse property is passed as a flag to sys_socket and sys_connect calls, e.g. something like this:
--- server reuses connections
io = sys_socket(…, REUSE);
while (true) {
cio = sys_accept(io);
sys_read(io, …);
sys_write(io, …);
sys_close(io);
}
--- client reuses connections
IO *io = NULL;
while (true) {
io = sys_connect(…, io, REUSE);
sys_read(io, …);
sys_write(io, …);
sys_close(io);
}
---
then sys_connect and sys_close can send the corresponding terminators if required, but of course this idea is very raw.
2.) indeed, committing a transaction right after http_200 is a great balance between performance and usability (i.e. canceling a transaction while still receiving the function call result).
- Ostap
I did another round of code review and found a couple of small things:
* comment on sys_proxy regarding the invocation result is confusing ("successful transfer" should be no errors)
* i think that the double buffering introduced in sys_proxy can be reverted
* it would be less error prone to use something like -1 for terminator in sys_term
* MAX_BLOCK size is quite weird (66560)