Skip to content

Commit b2a449c

Browse files
FiveTechSoftclaude
andcommitted
fix(network): TCP_NODELAY on every wire connection (Nagle off)
The OpenADS wire protocol is strict ping-pong: 1 client request → 1 server response per ABI call. With Nagle's algorithm on (the kernel default), small frames accumulate up to ~40-200 ms before the kernel actually flushes them. On a 20-RTT xbrowse PgDn that's 800 ms of pure scheduler-induced delay even after M12.17/18/19 collapsed the wire-call count to its theoretical minimum. Disable Nagle right after accept() and connect() succeed on both platform sockets: setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) POSIX side picks up the matching <netinet/tcp.h> include. Listener socket is unaffected; we only flip the per-connection sockets, where the latency cost actually lives. No protocol change. Existing 368 / 368 unit tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent bef7ce3 commit b2a449c

2 files changed

Lines changed: 27 additions & 0 deletions

File tree

src/network/socket_posix.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <cstring>
77
#include <errno.h>
88
#include <netinet/in.h>
9+
#include <netinet/tcp.h>
910
#include <sys/socket.h>
1011
#include <unistd.h>
1112

@@ -60,6 +61,16 @@ util::Result<PeerAddr> socket_peer_addr(const Socket& sock) {
6061
static_cast<std::uint16_t>(ntohs(addr.sin_port))};
6162
}
6263

64+
// M12.20 — disable Nagle on every per-connection socket. The
65+
// wire protocol is strict request/response (ping-pong), so the
66+
// kernel's Nagle delay (up to 200 ms accumulating small frames)
67+
// is pure latency tax. xbrowse PgDn × 20 RTT × 40 ms Nagle =
68+
// ~800 ms of pure delay per repaint pre-fix.
69+
static void disable_nagle(int s) {
70+
int on = 1;
71+
(void)::setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
72+
}
73+
6374
util::Result<Socket> accept_one(Socket& listener) {
6475
sockaddr_in addr{};
6576
socklen_t len = sizeof(addr);
@@ -68,6 +79,7 @@ util::Result<Socket> accept_one(Socket& listener) {
6879
if (c < 0) {
6980
return util::Error{5000, errno, "accept() failed", ""};
7081
}
82+
disable_nagle(c);
7183
Socket out;
7284
out.handle = static_cast<std::uintptr_t>(c);
7385
return out;
@@ -87,6 +99,7 @@ util::Result<Socket> connect_tcp(const std::string& host,
8799
int e = errno; ::close(s);
88100
return util::Error{5000, e, "connect() failed", host};
89101
}
102+
disable_nagle(s);
90103
Socket out;
91104
out.handle = static_cast<std::uintptr_t>(s);
92105
return out;

src/network/socket_win32.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ util::Result<PeerAddr> socket_peer_addr(const Socket& sock) {
8484
static_cast<std::uint16_t>(ntohs(addr.sin_port))};
8585
}
8686

87+
// M12.20 — disable Nagle on every per-connection socket. The
88+
// wire protocol is strict request/response (ping-pong), so the
89+
// kernel's Nagle delay (up to 200 ms accumulating small frames)
90+
// is pure latency tax. xbrowse PgDn × 20 RTT × 40 ms Nagle =
91+
// ~800 ms of pure delay per repaint pre-fix.
92+
static void disable_nagle(SOCKET s) {
93+
int on = 1;
94+
(void)::setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
95+
reinterpret_cast<const char*>(&on),
96+
sizeof(on));
97+
}
98+
8799
util::Result<Socket> accept_one(Socket& listener) {
88100
sockaddr_in addr{};
89101
int len = sizeof(addr);
@@ -93,6 +105,7 @@ util::Result<Socket> accept_one(Socket& listener) {
93105
return util::Error{5000, WSAGetLastError(),
94106
"accept() failed", ""};
95107
}
108+
disable_nagle(c);
96109
Socket out;
97110
out.handle = static_cast<std::uintptr_t>(c);
98111
return out;
@@ -115,6 +128,7 @@ util::Result<Socket> connect_tcp(const std::string& host,
115128
int e = WSAGetLastError(); closesocket(s);
116129
return util::Error{5000, e, "connect() failed", host};
117130
}
131+
disable_nagle(s);
118132
Socket out;
119133
out.handle = static_cast<std::uintptr_t>(s);
120134
return out;

0 commit comments

Comments
 (0)