Last active
August 29, 2015 14:19
-
-
Save markpapadakis/e18e235909f72ff8e912 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| bool TrySend(connection *const c) | |
| { | |
| iovec iov[128]; | |
| int fd = c->fd; | |
| sendv: | |
| auto it = c->respTail; | |
| int32_t r; | |
| bool haveCork; | |
| // If we have multiple requests(therefore multiple writev() calls are likely required) | |
| // and/or have say data to stream using sendfile(), then we need a cork | |
| // We don't use sendfile(), but that's how it'd work. Also, if we did need sendfile() | |
| // c could have been == nullptr. | |
| if (!it->next) // Fast path: single request(no pipelining) | |
| { | |
| r = writev(fd, it->iov + it->iovCur, it->iovCnt - it->iovCur); | |
| haveCork = false; | |
| } | |
| else | |
| { | |
| // Need to reduce writev() calls to absolute minimum | |
| uint8_t i{0}; | |
| auto cur= it->iovCur; | |
| if (!SwitchNetwork::SetTCPCork(fd, 1)) | |
| haveCork = true; | |
| do | |
| { | |
| if (cur >= 127) | |
| { | |
| // Patch, starting from it->iovCnt - 127. Reset it afterwards | |
| const auto cnt = it->iovCnt; | |
| for (decltype(it->iovCnt) i = it->iovCur - 127; i != cnt; ++i) | |
| { | |
| auto &v = it->iov[i]; | |
| if (v.iov_len >= (1U<<30)) | |
| { | |
| v.iov_len -= 1U<<30; | |
| v.iov_base = it->content->At((uint32_t)(uintptr_t)v.iov_base); | |
| } | |
| } | |
| cur = it->iovCur = 0; | |
| } | |
| const auto n = Min<uint8_t>(sizeof_array(iov) - i, it->iovCnt - cur); | |
| (void)memcpy(iov + i, it->iov + it->iovCur, n * sizeof(iovec)); | |
| i+=n; | |
| cur = 0; | |
| } while (i != sizeof_array(iov) && (it = it->next)); | |
| // Timings: | |
| // 5%: 4 | |
| // 10%: 5 | |
| // 25%: 5 | |
| // 50%: 7 | |
| // 75%: 8 | |
| // 90%: 13 | |
| // 95%: 19 | |
| // 99%: 31 | |
| r = writev(c->fd, iov, i); | |
| } | |
| if (unlikely(r == -1)) | |
| { | |
| const auto err = errno; | |
| if (unlikely(haveCork)) | |
| SwitchNetwork::SetTCPCork(fd, 0); | |
| if (err == EAGAIN) | |
| { | |
| if (!c->needIoAvail) | |
| { | |
| c->needIoAvail = true; | |
| (void)poller.SetDataAndEvents(c->fd, c, POLLIN|POLLOUT); | |
| } | |
| } | |
| else if (err != EINTR) | |
| { | |
| Shutdown(c, __LINE__); | |
| return false; | |
| } | |
| return true; | |
| } | |
| for (it = c->respTail; r >= it->iov[it->iovCur].iov_len; ) | |
| { | |
| r-=it->iov[it->iovCur].iov_len; | |
| if (++(it->iovCur) == it->iovCnt) | |
| { | |
| auto *const n = it->next; | |
| PutResponse(it); | |
| it = c->respTail = n; | |
| if (!it) | |
| { | |
| if (unlikely(haveCork)) | |
| SwitchNetwork::SetTCPCork(fd, 0); | |
| if (!c->keepAlive) | |
| { | |
| Shutdown(c, __LINE__); | |
| return false; | |
| } | |
| else | |
| { | |
| c->respHead = nullptr; | |
| if (c->needIoAvail) | |
| { | |
| (void)poller.SetDataAndEvents(c->fd, c, POLLIN); | |
| c->needIoAvail = false; | |
| } | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| auto &v = it->iov[it->iovCur]; | |
| v.iov_len-=r; | |
| v.iov_base = (char *)v.iov_base + r; | |
| // We didn't get to send all the content out - because we are limited in terms of sizeof_array(iov) | |
| // so we need another short at it | |
| // Ideally, we 'd have a large enough iov[] anyway. | |
| // | |
| // However, this could have been because there is no more space left in the socket send buf | |
| // so it only accepted as much as it could. In this case, another call to writev() will | |
| // return EAGAIN. | |
| // | |
| // We could probably better deal with this (enter needIoAvail mode if not all scheduled | |
| // content was dispatched, instead of retrying). | |
| goto sendv; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment