mirror of https://github.com/qt/qthttpserver.git
IOChunkedTransfer: avoid going back to the event loop
By looping in readFromInput() we can pass as much data as possible to the `sink` without having to return to the event loop repeatedly. And, in writeToOutput(), if we exhaust the buffer, just call readFromInput() directly instead of queuing a meta call. Because readFromInput() _also_ calls writeToOutput() when there is data to write we now have to check for recursion before calling readFromInput(). This cuts the time tst_bench_QHttpServer_transfer::transferPayload() takes with the "qbuffer" data-tag from 2s to 0.5s on my machine. Task-number: QTBUG-125717 Pick-to: 6.8 Change-Id: I5f7255ca3f68b414d2ca73dd377893b04fe13247 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
b63114a3b1
commit
2ff6b4b8ae
|
@ -6,7 +6,6 @@
|
|||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtHttpServer/qabstracthttpserver.h>
|
||||
#include <QtHttpServer/qhttpserverrequest.h>
|
||||
|
@ -108,6 +107,8 @@ struct IOChunkedTransfer
|
|||
const QPointer<QIODevice> sink;
|
||||
const QMetaObject::Connection bytesWrittenConnection;
|
||||
const QMetaObject::Connection readyReadConnection;
|
||||
bool inRead = false;
|
||||
|
||||
IOChunkedTransfer(QIODevice *input, QIODevice *output) :
|
||||
source(input),
|
||||
sink(output),
|
||||
|
@ -149,18 +150,26 @@ struct IOChunkedTransfer
|
|||
|
||||
void readFromInput()
|
||||
{
|
||||
if (inRead)
|
||||
return;
|
||||
if (source.isNull())
|
||||
return;
|
||||
|
||||
if (!isBufferEmpty()) // We haven't consumed all the data yet.
|
||||
return;
|
||||
beginIndex = 0;
|
||||
endIndex = source->read(buffer, bufferSize);
|
||||
if (endIndex < 0) {
|
||||
endIndex = beginIndex; // Mark the buffer as empty
|
||||
qCWarning(lcHttpServerHttp1Handler, "Error reading chunk: %ls",
|
||||
qUtf16Printable(source->errorString()));
|
||||
} else if (endIndex) {
|
||||
QScopedValueRollback inReadGuard(inRead, true);
|
||||
|
||||
while (isBufferEmpty()) {
|
||||
beginIndex = 0;
|
||||
endIndex = source->read(buffer, bufferSize);
|
||||
if (endIndex < 0) {
|
||||
endIndex = beginIndex; // Mark the buffer as empty
|
||||
qCWarning(lcHttpServerHttp1Handler, "Error reading chunk: %ls",
|
||||
qUtf16Printable(source->errorString()));
|
||||
break;
|
||||
}
|
||||
if (endIndex == 0)
|
||||
break;
|
||||
memset(buffer + endIndex, 0, sizeof(buffer) - std::size_t(endIndex));
|
||||
writeToOutput();
|
||||
}
|
||||
|
@ -195,9 +204,9 @@ struct IOChunkedTransfer
|
|||
}
|
||||
beginIndex += writtenBytes;
|
||||
if (isBufferEmpty()) {
|
||||
if (source->bytesAvailable())
|
||||
QTimer::singleShot(0, source.data(), [this]() { readFromInput(); });
|
||||
else if (source->atEnd()) // Finishing
|
||||
if (source->bytesAvailable() && !inRead)
|
||||
readFromInput();
|
||||
else if (source->atEnd()) // Finishing
|
||||
source->deleteLater();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue