Skip to content
Permalink
Browse files

Improve performance of non-blocking reads by using maximum buffer size.

Since the introduction of blocking read drivers (e.g. IoHandleRead, TlsClient) the non-blocking drivers have used the same rules for determining maximum buffer size, i.e. read only as much as requested.  This is necessary so the blocking drivers don't get stuck waiting for data that might not be coming.

Instead mark blocking drivers so IoRead knows how much buffer to allow for the read.  The non-blocking drivers can now request the maximum number of bytes allowed by buffer-size.
  • Loading branch information...
dwsteele committed Apr 19, 2019
1 parent 0c866f5 commit c9168028c6c43d535a5663cb17ce93945951cb7e
@@ -14,6 +14,12 @@
<release-list>
<release date="XXXX-XX-XX" version="2.14dev" title="UNDER DEVELOPMENT">
<release-core-list>
<release-improvement-list>
<release-item>
<p>Improve performance of non-blocking reads by using maximum buffer size.</p>
</release-item>
</release-improvement-list>

<release-development-list>
<release-item>
<p>Add <code>unsigned int</code> <code>Variant</code> type and update code to use it.</p>
@@ -174,7 +174,7 @@ execOpen(Exec *this)

// Create wrapper interfaces that check process state
this->ioReadExec = ioReadNewP(
this, .read = (IoReadInterfaceRead)execRead, .eof = (IoReadInterfaceEof)execEof,
this, .block = true, .read = (IoReadInterfaceRead)execRead, .eof = (IoReadInterfaceEof)execEof,
.handle = (IoReadInterfaceHandle)execHandleRead);
ioReadOpen(this->ioReadExec);
this->ioWriteExec = ioWriteNewP(this, .write = (IoWriteInterfaceWrite)execWrite);
@@ -42,7 +42,7 @@ ioHandleReadNew(const String *name, int handle, TimeMSec timeout)
this = memNew(sizeof(IoHandleRead));
this->memContext = memContextCurrent();
this->io = ioReadNewP(
this, .eof = (IoReadInterfaceEof)ioHandleReadEof, .handle = (IoReadInterfaceHandle)ioHandleReadHandle,
this, .block = true, .eof = (IoReadInterfaceEof)ioHandleReadEof, .handle = (IoReadInterfaceHandle)ioHandleReadHandle,
.read = (IoReadInterfaceRead)ioHandleRead);
this->name = strDup(name);
this->handle = handle;
@@ -144,7 +144,7 @@ ioReadInternal(IoRead *this, Buffer *buffer, bool block)
bufUsedZero(this->input);

// If blocking then limit the amount of data requested
if (block && bufRemains(this->input) > bufRemains(buffer))
if (ioReadBlock(this) && bufRemains(this->input) > bufRemains(buffer))
bufLimitSet(this->input, bufRemains(buffer));

this->interface.read(this->driver, this->input, block);
@@ -305,6 +305,21 @@ ioReadClose(IoRead *this)
FUNCTION_LOG_RETURN_VOID();
}

/***********************************************************************************************************************************
Do reads block when more bytes are requested than are available to read?
***********************************************************************************************************************************/
bool
ioReadBlock(const IoRead *this)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(IO_READ, this);
FUNCTION_TEST_END();

ASSERT(this != NULL);

FUNCTION_TEST_RETURN(this->interface.block);
}

/***********************************************************************************************************************************
Is IO at EOF?
@@ -352,6 +367,7 @@ ioReadFilterGroupSet(IoRead *this, IoFilterGroup *filterGroup)
ASSERT(filterGroup != NULL);
ASSERT(this->filterGroup == NULL);
ASSERT(!this->opened && !this->closed);
ASSERT(!ioReadBlock(this));

this->filterGroup = filterGroup;

@@ -28,6 +28,7 @@ void ioReadClose(IoRead *this);
/***********************************************************************************************************************************
Getters/Setters
***********************************************************************************************************************************/
bool ioReadBlock(const IoRead *this);
bool ioReadEof(const IoRead *this);
const IoFilterGroup *ioReadFilterGroup(const IoRead *this);
void ioReadFilterGroupSet(IoRead *this, IoFilterGroup *filterGroup);
@@ -17,6 +17,7 @@ typedef size_t (*IoReadInterfaceRead)(void *driver, Buffer *buffer, bool block);

typedef struct IoReadInterface
{
bool block; // Do reads block when buffer is larger than available bytes?
IoReadInterfaceEof eof;
IoReadInterfaceClose close;
IoReadInterfaceHandle handle;
@@ -414,7 +414,8 @@ tlsClientOpen(TlsClient *this)
// Create read and write interfaces
this->write = ioWriteNewP(this, .write = (IoWriteInterfaceWrite)tlsClientWrite);
ioWriteOpen(this->write);
this->read = ioReadNewP(this, .eof = (IoReadInterfaceEof)tlsClientEof, .read = (IoReadInterfaceRead)tlsClientRead);
this->read = ioReadNewP(
this, .block = true, .eof = (IoReadInterfaceEof)tlsClientEof, .read = (IoReadInterfaceRead)tlsClientRead);
ioReadOpen(this->read);
}
MEM_CONTEXT_END();
@@ -551,10 +551,13 @@ testRun(void)
TEST_ERROR(ioRead(ioHandleReadIo(read), buffer), FileReadError, "unable to read data from read test after 1000ms");
TEST_RESULT_UINT(bufSize(buffer), 16, "buffer is only partially read");

// Read a buffer that is transmitted in two parts
// Read a buffer that is transmitted in two parts with blocking on the read side
buffer = bufNew(16);
bufLimitSet(buffer, 12);

TEST_RESULT_UINT(ioRead(ioHandleReadIo(read), buffer), 16, "read buffer");
TEST_RESULT_UINT(ioRead(ioHandleReadIo(read), buffer), 12, "read buffer");
bufLimitClear(buffer);
TEST_RESULT_UINT(ioRead(ioHandleReadIo(read), buffer), 4, "read buffer");
TEST_RESULT_STR(strPtr(strNewBuf(buffer)), "1234567812345678", "check buffer");

// Check EOF

0 comments on commit c916802

Please sign in to comment.
You can’t perform that action at this time.