perf+sec: 15 improvements across consensus, DB, network, sync
CONSENSUS SECURITY (main.cpp): - Re-enable PoS kernel verification post-IBD (was unconditionally disabled) - Re-enable coinstake reward validation post-IBD (was commented out) - Re-enable anti-spam difficulty check (was if(false && ...)) SYNC PERFORMANCE (main.cpp): - Batch address index writes in ConnectBlock (hundreds of DB ops → one per address) - Throttle IBD printfs (per-block → per-10K-blocks or fDebug-gated) DATABASE (txdb-rocksdb.cpp/h, txdb-base.cpp): - Non-batched WriteRaw: WAL sync=false (was fsync per write) - UTXO cache: FIFO eviction → true LRU with access-order tracking - RocksDB memtable: 64MB → 256MB + max_write_buffer_number=4 - pendingBatch: std::map → std::unordered_map (O(log n) → O(1)) - max_open_files: 1000 → unlimited NETWORK (net.cpp, netbase.cpp): - TCP_NODELAY on all sockets (disable Nagle's algorithm) - SO_KEEPALIVE on all sockets (faster dead-peer detection) - Adaptive MilliSleep: 1ms during IBD, 10ms otherwise - writev() scatter-gather I/O for send() coalescing (up to 16 msgs/syscall) - O(1) CountInFlight counter (was O(n) scan of entire header map)
This commit is contained in:
+71
-9
@@ -21,6 +21,8 @@
|
||||
|
||||
#ifdef WIN32
|
||||
#include <string.h>
|
||||
#else
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_UPNP
|
||||
@@ -831,36 +833,96 @@ void SocketSendData(CNode *pnode)
|
||||
std::deque<CSerializeData>::iterator it = pnode->vSendMsg.begin();
|
||||
|
||||
while (it != pnode->vSendMsg.end()) {
|
||||
#ifndef WIN32
|
||||
// Coalesce up to MAX_IOV queued messages into a single syscall using
|
||||
// scatter-gather I/O. On Linux we use sendmsg() so we can pass
|
||||
// MSG_NOSIGNAL | MSG_DONTWAIT; on other POSIX systems (e.g. BSD where
|
||||
// SO_NOSIGPIPE is already set on the socket) we fall back to writev().
|
||||
static const int MAX_IOV = 16;
|
||||
struct iovec iov[MAX_IOV];
|
||||
int iovcnt = 0;
|
||||
std::deque<CSerializeData>::iterator batchEnd = it;
|
||||
|
||||
for (; batchEnd != pnode->vSendMsg.end() && iovcnt < MAX_IOV; ++batchEnd, ++iovcnt) {
|
||||
const CSerializeData &data = *batchEnd;
|
||||
size_t off = (batchEnd == it) ? pnode->nSendOffset : 0;
|
||||
assert(data.size() > off);
|
||||
iov[iovcnt].iov_base = const_cast<char*>(&data[off]);
|
||||
iov[iovcnt].iov_len = data.size() - off;
|
||||
}
|
||||
|
||||
if (iovcnt == 0)
|
||||
break;
|
||||
|
||||
ssize_t nBytes;
|
||||
#ifdef MSG_NOSIGNAL
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = iovcnt;
|
||||
nBytes = sendmsg(pnode->hSocket, &msg, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
#else
|
||||
nBytes = writev(pnode->hSocket, iov, iovcnt);
|
||||
#endif
|
||||
if (nBytes > 0) {
|
||||
pnode->nLastSend = GetTime();
|
||||
pnode->nSendBytes += nBytes;
|
||||
|
||||
// Consume nBytes across the coalesced messages
|
||||
while (it != batchEnd && nBytes > 0) {
|
||||
const CSerializeData &data = *it;
|
||||
size_t remaining = data.size() - pnode->nSendOffset;
|
||||
if ((size_t)nBytes >= remaining) {
|
||||
nBytes -= remaining;
|
||||
pnode->nSendSize -= data.size();
|
||||
pnode->nSendOffset = 0;
|
||||
++it;
|
||||
} else {
|
||||
pnode->nSendOffset += nBytes;
|
||||
nBytes = 0;
|
||||
}
|
||||
}
|
||||
// Socket buffer full mid-batch — wait for next cycle
|
||||
if (it != batchEnd)
|
||||
break;
|
||||
} else if (nBytes < 0) {
|
||||
int nErr = WSAGetLastError();
|
||||
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) {
|
||||
printf("socket send error %d\n", nErr);
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
// nBytes == 0: peer closed
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// Windows: individual send() calls
|
||||
const CSerializeData &data = *it;
|
||||
assert(data.size() > pnode->nSendOffset);
|
||||
int nBytes = send(pnode->hSocket, &data[pnode->nSendOffset], data.size() - pnode->nSendOffset, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
if (nBytes > 0) {
|
||||
pnode->nLastSend = GetTime();
|
||||
pnode->nSendOffset += nBytes;
|
||||
|
||||
pnode->nSendBytes += nBytes;
|
||||
|
||||
pnode->nSendBytes += nBytes;
|
||||
if (pnode->nSendOffset == data.size()) {
|
||||
pnode->nSendOffset = 0;
|
||||
pnode->nSendSize -= data.size();
|
||||
it++;
|
||||
} else {
|
||||
// could not send full message; stop sending more
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (nBytes < 0) {
|
||||
// error
|
||||
int nErr = WSAGetLastError();
|
||||
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS)
|
||||
{
|
||||
if (nErr != WSAEWOULDBLOCK && nErr != WSAEMSGSIZE && nErr != WSAEINTR && nErr != WSAEINPROGRESS) {
|
||||
printf("socket send error %d\n", nErr);
|
||||
pnode->CloseSocketDisconnect();
|
||||
}
|
||||
}
|
||||
// couldn't send anything at all
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (it == pnode->vSendMsg.end()) {
|
||||
@@ -1221,7 +1283,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
|
||||
if (fShutdown)
|
||||
return;
|
||||
MilliSleep(10);
|
||||
MilliSleep(IsInitialBlockDownload() ? 1 : 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user