Add large non-ssl, non-compressed WebSocket message sending optimization
This commit is contained in:
+53
-34
@@ -105,48 +105,67 @@ public:
|
||||
|
||||
/* If we are subscribers and have messages to drain we need to drain them here to stay synced */
|
||||
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||
if (webSocketData->subscriber) {
|
||||
/* This will call back into us, send. */
|
||||
webSocketContextData->topicTree->drain(webSocketData->subscriber);
|
||||
}
|
||||
|
||||
/* Transform the message to compressed domain if requested */
|
||||
if (compress) {
|
||||
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||
|
||||
/* Check and correct the compress hint. It is never valid to compress 0 bytes */
|
||||
if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) {
|
||||
LoopData *loopData = Super::getLoopData();
|
||||
/* Compress using either shared or dedicated deflationStream */
|
||||
if (webSocketData->deflationStream) {
|
||||
message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false);
|
||||
/* Special path for long sends of non-compressed, non-SSL messages */
|
||||
if (message.length() >= 16 * 1024 && !compress && !SSL && !webSocketData->subscriber && getBufferedAmount() == 0 && Super::getLoopData()->corkOffset == 0) {
|
||||
char header[14];
|
||||
int header_length = (int) protocol::formatMessage<isServer>(header, nullptr, 0, opCode, message.length(), compress, fin);
|
||||
int written = us_socket_write2(0, (struct us_socket_t *)this, header, header_length, message.data(), (int) message.length());
|
||||
|
||||
if (written != header_length + (int) message.length()) {
|
||||
/* Buffer up backpressure */
|
||||
if (written > header_length) {
|
||||
webSocketData->buffer.append(message.data() + written, message.length() - (size_t) written);
|
||||
} else {
|
||||
message = loopData->deflationStream->deflate(loopData->zlibContext, message, true);
|
||||
webSocketData->buffer.append(header + written, (size_t) header_length - (size_t) written);
|
||||
}
|
||||
} else {
|
||||
compress = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Get size, allocate size, write if needed */
|
||||
size_t messageFrameSize = protocol::messageFrameSize(message.length());
|
||||
auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize);
|
||||
protocol::formatMessage<isServer>(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin);
|
||||
if (webSocketData->subscriber) {
|
||||
/* This will call back into us, send. */
|
||||
webSocketContextData->topicTree->drain(webSocketData->subscriber);
|
||||
}
|
||||
|
||||
/* Depending on size of message we have different paths */
|
||||
if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) {
|
||||
/* This is a drain */
|
||||
auto[written, failed] = Super::write(nullptr, 0);
|
||||
if (failed) {
|
||||
/* Return false for failure, skipping to reset the timeout below */
|
||||
return BACKPRESSURE;
|
||||
/* Transform the message to compressed domain if requested */
|
||||
if (compress) {
|
||||
WebSocketData *webSocketData = (WebSocketData *) Super::getAsyncSocketData();
|
||||
|
||||
/* Check and correct the compress hint. It is never valid to compress 0 bytes */
|
||||
if (message.length() && opCode < 3 && webSocketData->compressionStatus == WebSocketData::ENABLED) {
|
||||
LoopData *loopData = Super::getLoopData();
|
||||
/* Compress using either shared or dedicated deflationStream */
|
||||
if (webSocketData->deflationStream) {
|
||||
message = webSocketData->deflationStream->deflate(loopData->zlibContext, message, false);
|
||||
} else {
|
||||
message = loopData->deflationStream->deflate(loopData->zlibContext, message, true);
|
||||
}
|
||||
} else {
|
||||
compress = false;
|
||||
}
|
||||
}
|
||||
} else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) {
|
||||
/* Uncork if we came here uncorked */
|
||||
auto [written, failed] = Super::uncork();
|
||||
if (failed) {
|
||||
return BACKPRESSURE;
|
||||
|
||||
/* Get size, allocate size, write if needed */
|
||||
size_t messageFrameSize = protocol::messageFrameSize(message.length());
|
||||
auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize);
|
||||
protocol::formatMessage<isServer>(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin);
|
||||
|
||||
/* Depending on size of message we have different paths */
|
||||
if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) {
|
||||
/* This is a drain */
|
||||
auto[written, failed] = Super::write(nullptr, 0);
|
||||
if (failed) {
|
||||
/* Return false for failure, skipping to reset the timeout below */
|
||||
return BACKPRESSURE;
|
||||
}
|
||||
} else if (sendBufferAttribute == SendBufferAttribute::NEEDS_UNCORK) {
|
||||
/* Uncork if we came here uncorked */
|
||||
auto [written, failed] = Super::uncork();
|
||||
if (failed) {
|
||||
return BACKPRESSURE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Every successful send resets the timeout */
|
||||
|
||||
+1
-1
Submodule uSockets updated: b950efd6b1...0866daff30
Reference in New Issue
Block a user