diff options
author | dormando <dormando@rydia.net> | 2023-02-08 17:22:27 -0800 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2023-02-08 17:22:27 -0800 |
commit | 3722d0d12be07ede1a8c3081c2e8e0a4c2b477b5 (patch) | |
tree | b63cc455977461b2f13be416f85d8caa3a76210e | |
parent | f06dc8ca278b218414340680baf34fdccbf52b6f (diff) | |
download | memcached-3722d0d12be07ede1a8c3081c2e8e0a4c2b477b5.tar.gz |
proxy: fix write flushing bugs
1) the event flags were not being used from the result of the
flush_pending_write() function, causing it to not listen on WRITE
events in some cases.
2) be->can_write flag was not being set on short writes; old iterations
of code would loop-write until EAGAIN but this does not.
This prevented the code from listening for WRITE events.
3) if many short writes are happening, a successful read event was
overwriting the WRITE event with a READ event, instead of READ|WRITE.
fixed via the be->can_write flag fix from 2).
-rw-r--r-- | proxy_network.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/proxy_network.c b/proxy_network.c index d893f3f..a80284c 100644 --- a/proxy_network.c +++ b/proxy_network.c @@ -856,7 +856,7 @@ static void proxy_event_handler(evutil_socket_t fd, short which, void *arg) { _reset_bad_backend(be, P_BE_FAIL_WRITING); _backend_failed(be); } else { - flags = be->can_write ? EV_READ|EV_TIMEOUT : EV_READ|EV_WRITE|EV_TIMEOUT; + flags |= EV_TIMEOUT; _set_event(be, t->base, flags, be->tunables.read, proxy_backend_handler); } } @@ -1276,12 +1276,6 @@ static bool _post_pending_write(mcp_backend_t *be, ssize_t sent) { bool flushed = true; if (io->flushed) continue; - if (sent <= 0) { - // really shouldn't be negative, though. - assert(sent >= 0); - break; - } - if (sent >= io->iovbytes) { // short circuit for common case. sent -= io->iovbytes; @@ -1306,10 +1300,15 @@ static bool _post_pending_write(mcp_backend_t *be, ssize_t sent) { if (flushed) { did_flush = flushed; } + if (sent <= 0) { + // really shouldn't be negative, though. + assert(sent >= 0); + break; + } } // for // resume the flush from this point. - if (io != NULL) { + if (io != NULL && !io->flushed) { be->io_next = io; } else { be->io_next = NULL; @@ -1334,6 +1333,7 @@ static int _flush_pending_write(mcp_backend_t *be) { } // still have unflushed pending IO's, check for write and re-loop. if (be->io_next) { + be->can_write = false; flags |= EV_WRITE; } } else if (sent == -1) { @@ -1510,6 +1510,9 @@ static void proxy_backend_handler(const int fd, const short which, void *arg) { // Still pending requests to read or write. if (!STAILQ_EMPTY(&be->io_head)) { flags |= EV_READ; // FIXME (v2): might not be necessary here, but ensures we get a disconnect event. + if (!be->can_write) { + flags |= EV_WRITE; + } _set_event(be, be->event_thread->base, flags, tmp_time, proxy_backend_handler); } } |