In my attempts to understand the mechanics of TSIOBufferCopy I found the
following function definition in InkIOCoreAPI.cc
int64_t
TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length,
int64_t offset)
{
sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS);
sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS);
sdk_assert((length >= 0) && (offset >= 0));
MIOBuffer *b = (MIOBuffer *)bufp;
IOBufferReader *r = (IOBufferReader *)readerp;
return b->write(r, length, offset);
}
Note that it is undocumented but apparently the b->write(r, length, offset)
does the work.
I believe I found the declaration of that function in I_IOBuffer.h One thing
that sort of stuck out to me in the set of code comments below, was the fact
that it says
"Should it be necessary to make a large number of small transfers, it's
preferable to use a interface that copies the data rather than sharing blocks
to prevent
a build of blocks on the buffer"
What confuses me is isn't TSIOBufferCopy supposed to be an interface that
copies data rather than sharing blocks?
/**
Add by data from IOBufferReader r to the this buffer by reference. If
len is INT64_MAX, all available data on the reader is added. If len is
less than INT64_MAX, the smaller of len or the amount of data on the
buffer is added. If offset is greater than zero, than the offset
bytes of data at the front of the reader are skipped. Bytes skipped
by offset reduce the number of bytes available on the reader used
in the amount of data to add computation. write() does not respect
watermarks or buffer size limits. Users of write must implement
their own flow control. Returns the number of bytes added. Each
write() call creates a new IOBufferBlock, even if it is for one
byte. As such, it's necessary to exercise caution in any code that
repeatedly transfers data from one buffer to another, especially if
the data is being read over the network as it may be coming in very
small chunks. Because deallocation of outstanding buffer blocks is
recursive, it's possible to overrun the stack if too many blocks
have been added to the buffer chain. It's imperative that users
both implement their own flow control to prevent too many bytes
from becoming outstanding on a buffer that the write() call is
being used and that care be taken to ensure the transfers are of a
minimum size. Should it be necessary to make a large number of small
transfers, it's preferable to use a interface that copies the data
rather than sharing blocks to prevent a build of blocks on the buffer.
*/
inkcoreapi int64_t write(IOBufferReader * r, int64_t len = INT64_MAX, int64_t
offset = 0);
Also, the comments say that the return value of write is the actual number of
bytes written. Is it safe to assume that the return value will equal len
should offset be 0? If so, when you are simply trying to copy data from
upstream to downstream and you subsequently make a calls such as:
/* Copy the data from the read buffer to the output buffer. */
bytesWritten = TSIOBufferCopy(TSVIOBufferGet(data->output_vio),
TSVIOReaderGet(input_vio), towrite, 0);
/* Tell the read buffer that we have read 'towrite' bytes of data
* and are no longer interested in it.
*/
TSIOBufferReaderConsume(TSVIOReaderGet(input_vio), bytesWritten); // Should
second param be bytesWritten or should it be towrite?
/* Increment the input VIO nDone value to reflect how much
* data we've copied from the upstream and written to the
* downstream.
*/
TSVIONDoneSet(input_vio, TSVIONDoneGet(input_vio) + bytesWritten); // Should
Second param be TSVIONDoneGet(input_vio) + bytesWritten or
TSVIONDoneGet(input_vio) + towrite?