Use writev
This commit is contained in:
62
src/main.cpp
62
src/main.cpp
@@ -10,11 +10,13 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <limits.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -147,18 +149,13 @@ struct Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Message {
|
std::deque<std::string_view, ArenaStlAllocator<std::string_view>> messages{
|
||||||
// Owned by Connection::arena
|
ArenaStlAllocator<std::string_view>{&arena}};
|
||||||
std::string_view s;
|
|
||||||
int written = 0;
|
|
||||||
};
|
|
||||||
std::deque<Message, ArenaStlAllocator<Message>> messages{
|
|
||||||
ArenaStlAllocator<Message>{&arena}};
|
|
||||||
// Copies s into arena, and appends to messages
|
// Copies s into arena, and appends to messages
|
||||||
void appendMessage(std::string_view s) {
|
void appendMessage(std::string_view s) {
|
||||||
char *arena_str = arena.allocate<char>(s.size());
|
char *arena_str = arena.allocate<char>(s.size());
|
||||||
std::memcpy(arena_str, s.data(), s.size());
|
std::memcpy(arena_str, s.data(), s.size());
|
||||||
messages.emplace_back(std::string_view(arena_str, s.size()), 0);
|
messages.emplace_back(arena_str, s.size());
|
||||||
}
|
}
|
||||||
// Whether or not to close the connection after completing writing the
|
// Whether or not to close the connection after completing writing the
|
||||||
// response
|
// response
|
||||||
@@ -192,11 +189,28 @@ struct Connection {
|
|||||||
|
|
||||||
bool writeBytes() {
|
bool writeBytes() {
|
||||||
while (!messages.empty()) {
|
while (!messages.empty()) {
|
||||||
auto &front = messages.front();
|
// Build iovec array up to IOV_MAX limit
|
||||||
int w;
|
struct iovec iov[IOV_MAX];
|
||||||
|
int iov_count = 0;
|
||||||
|
|
||||||
|
for (auto it = messages.begin();
|
||||||
|
it != messages.end() && iov_count < IOV_MAX; ++it) {
|
||||||
|
const auto &msg = *it;
|
||||||
|
if (msg.size() > 0) {
|
||||||
|
iov[iov_count] = {
|
||||||
|
const_cast<void *>(static_cast<const void *>(msg.data())),
|
||||||
|
msg.size()};
|
||||||
|
iov_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iov_count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t w;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
w = write(fd, front.s.data() + front.written,
|
w = writev(fd, iov, iov_count);
|
||||||
front.s.size() - front.written);
|
|
||||||
if (w == -1) {
|
if (w == -1) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
continue; // Standard practice: retry on signal interruption
|
continue; // Standard practice: retry on signal interruption
|
||||||
@@ -204,15 +218,29 @@ struct Connection {
|
|||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
perror("write");
|
perror("writev");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(w != 0);
|
|
||||||
front.written += w;
|
assert(w > 0);
|
||||||
if (front.written == int(front.s.size())) {
|
|
||||||
messages.pop_front();
|
// Handle partial writes by updating string_view data/size
|
||||||
|
size_t bytes_written = static_cast<size_t>(w);
|
||||||
|
while (bytes_written > 0 && !messages.empty()) {
|
||||||
|
auto &front = messages.front();
|
||||||
|
|
||||||
|
if (bytes_written >= front.size()) {
|
||||||
|
// This message is completely written
|
||||||
|
bytes_written -= front.size();
|
||||||
|
messages.pop_front();
|
||||||
|
} else {
|
||||||
|
// Partial write of this message - update string_view
|
||||||
|
front = std::string_view(front.data() + bytes_written,
|
||||||
|
front.size() - bytes_written);
|
||||||
|
bytes_written = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(messages.empty());
|
assert(messages.empty());
|
||||||
|
|||||||
Reference in New Issue
Block a user