416 lines
12 KiB
C++
416 lines
12 KiB
C++
/*
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
|
|
compliance with the License. You may obtain a copy of the License
|
|
at http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
|
|
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
|
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
|
|
|
|
See the Apache Version 2.0 License for specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
#include "channelmemorybuffers.h"
|
|
#include "channelreader.h"
|
|
#include "channelwriter.h"
|
|
|
|
#pragma unmanaged
|
|
|
|
|
|
RChannelReaderBuffer::Current::Current(Size_t initialStartOffset,
|
|
Size_t finalEndOffset,
|
|
DryadLockedMemoryBuffer**
|
|
bufferArray,
|
|
size_t nBuffers,
|
|
Size_t offset)
|
|
{
|
|
m_currentBuffer = 0;
|
|
m_currentBufferBase = 0;
|
|
m_currentHeadCutLength = initialStartOffset;
|
|
m_currentTailOffset = 0;
|
|
|
|
SetTailBufferData(bufferArray, nBuffers, finalEndOffset);
|
|
|
|
while (offset >= m_currentTailOffset)
|
|
{
|
|
++m_currentBuffer;
|
|
LogAssert(m_currentBuffer < nBuffers);
|
|
|
|
m_currentBufferBase = m_currentTailOffset;
|
|
m_currentHeadCutLength = 0;
|
|
|
|
SetTailBufferData(bufferArray, nBuffers, finalEndOffset);
|
|
}
|
|
}
|
|
|
|
void* RChannelReaderBuffer::Current::
|
|
GetDataAddress(DryadLockedMemoryBuffer** bufferArray,
|
|
Size_t offset,
|
|
Size_t *puSize,
|
|
Size_t *puPriorSize)
|
|
{
|
|
LogAssert(offset >= m_currentBufferBase &&
|
|
offset < m_currentTailOffset);
|
|
|
|
Size_t offsetInAvailable = offset - m_currentBufferBase;
|
|
Size_t offsetInBuffer = offsetInAvailable + m_currentHeadCutLength;
|
|
Size_t remaining = m_currentTailOffset - offset;
|
|
|
|
void* dataAddress =
|
|
bufferArray[m_currentBuffer]->GetDataAddress(offsetInBuffer,
|
|
puSize,
|
|
puPriorSize);
|
|
LogAssert(dataAddress != NULL);
|
|
|
|
if (*puSize > remaining)
|
|
{
|
|
*puSize = remaining;
|
|
}
|
|
|
|
if (puPriorSize != NULL && *puPriorSize > offsetInAvailable)
|
|
{
|
|
*puPriorSize = offsetInAvailable;
|
|
}
|
|
|
|
return dataAddress;
|
|
}
|
|
|
|
void RChannelReaderBuffer::Current::
|
|
SetTailBufferData(DryadLockedMemoryBuffer** bufferArray,
|
|
size_t nBuffers,
|
|
Size_t finalEndOffset)
|
|
{
|
|
Size_t bSize = bufferArray[m_currentBuffer]->GetAvailableSize();
|
|
|
|
if (m_currentBuffer == nBuffers-1)
|
|
{
|
|
LogAssert(finalEndOffset >= m_currentHeadCutLength);
|
|
LogAssert(finalEndOffset <= bSize);
|
|
|
|
m_currentTailOffset += (finalEndOffset - m_currentHeadCutLength);
|
|
}
|
|
else
|
|
{
|
|
m_currentTailOffset += (bSize - m_currentHeadCutLength);
|
|
}
|
|
}
|
|
|
|
|
|
RChannelReaderBuffer::RChannelReaderBuffer(DryadLockedBufferList* bufferList,
|
|
Size_t startOffset,
|
|
Size_t endOffset)
|
|
{
|
|
m_nBuffers = bufferList->CountLinks();
|
|
LogAssert(m_nBuffers > 0);
|
|
m_bufferArray = new DryadLockedMemoryBuffer *[m_nBuffers];
|
|
|
|
LogAssert(m_uAllocatedSize == 0);
|
|
size_t i;
|
|
DrBListEntry* listEntry = bufferList->GetHead();
|
|
for (i=0; i < m_nBuffers; ++i)
|
|
{
|
|
LogAssert(listEntry != NULL);
|
|
m_bufferArray[i] = bufferList->CastOut(listEntry);
|
|
m_bufferArray[i]->IncRef();
|
|
m_uAllocatedSize += m_bufferArray[i]->GetAvailableSize();
|
|
listEntry = bufferList->GetNext(listEntry);
|
|
}
|
|
LogAssert(listEntry == NULL);
|
|
|
|
Initialise(startOffset, endOffset);
|
|
}
|
|
|
|
RChannelReaderBuffer::RChannelReaderBuffer(ChannelDataBufferList* bufferList,
|
|
Size_t startOffset,
|
|
Size_t endOffset)
|
|
{
|
|
m_nBuffers = bufferList->CountLinks();
|
|
LogAssert(m_nBuffers > 0);
|
|
m_bufferArray = new DryadLockedMemoryBuffer *[m_nBuffers];
|
|
|
|
LogAssert(m_uAllocatedSize == 0);
|
|
size_t i;
|
|
DrBListEntry* listEntry = bufferList->GetHead();
|
|
for (i=0; i < m_nBuffers; ++i)
|
|
{
|
|
LogAssert(listEntry != NULL);
|
|
m_bufferArray[i] = (bufferList->CastOut(listEntry))->GetData();
|
|
m_bufferArray[i]->IncRef();
|
|
m_uAllocatedSize += m_bufferArray[i]->GetAvailableSize();
|
|
listEntry = bufferList->GetNext(listEntry);
|
|
}
|
|
LogAssert(listEntry == NULL);
|
|
|
|
Initialise(startOffset, endOffset);
|
|
}
|
|
|
|
void RChannelReaderBuffer::Initialise(Size_t startOffset, Size_t endOffset)
|
|
{
|
|
m_fIsGrowable = false;
|
|
|
|
LogAssert(startOffset <= m_bufferArray[0]->GetAvailableSize());
|
|
LogAssert(endOffset <= m_bufferArray[m_nBuffers-1]->GetAvailableSize());
|
|
Size_t tailCutLength =
|
|
m_bufferArray[m_nBuffers-1]->GetAvailableSize() - endOffset;
|
|
LogAssert(m_uAllocatedSize >= (startOffset + tailCutLength));
|
|
m_uAllocatedSize -= (startOffset + tailCutLength);
|
|
|
|
SetAvailableSize(m_uAllocatedSize);
|
|
|
|
m_initialStartOffset = startOffset;
|
|
m_finalEndOffset = endOffset;
|
|
}
|
|
|
|
RChannelReaderBuffer::~RChannelReaderBuffer()
|
|
{
|
|
size_t i;
|
|
|
|
for (i=0; i<m_nBuffers; ++i)
|
|
{
|
|
m_bufferArray[i]->DecRef();
|
|
}
|
|
delete [] m_bufferArray;
|
|
}
|
|
|
|
void* RChannelReaderBuffer::GetDataAddress(Size_t uOffset,
|
|
Size_t *puSize,
|
|
Size_t *puPriorSize)
|
|
{
|
|
if (uOffset >= m_uAllocatedSize)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Current current(m_initialStartOffset, m_finalEndOffset,
|
|
m_bufferArray, m_nBuffers, uOffset);
|
|
|
|
void* dataAddress = current.GetDataAddress(m_bufferArray,
|
|
uOffset,
|
|
puSize,
|
|
puPriorSize);
|
|
|
|
return dataAddress;
|
|
}
|
|
|
|
void RChannelReaderBuffer::IncreaseAllocatedSize(Size_t uSize)
|
|
{
|
|
LogAssert(uSize <= m_uAllocatedSize);
|
|
}
|
|
|
|
|
|
RChannelWriterBuffer::
|
|
RChannelWriterBuffer(RChannelBufferWriter* bufferProvider,
|
|
DryadFixedBufferList* bufferList)
|
|
{
|
|
m_bufferProvider = bufferProvider;
|
|
m_bufferList = bufferList;
|
|
if (m_bufferList->IsEmpty() == false)
|
|
{
|
|
LogAssert(m_bufferList->CountLinks() == 1);
|
|
DryadFixedMemoryBuffer* currentBuffer =
|
|
m_bufferList->CastOut(m_bufferList->GetHead());
|
|
|
|
LogAssert(currentBuffer->GetAllocatedSize() >
|
|
currentBuffer->GetAvailableSize());
|
|
|
|
m_baseBufferOffset = currentBuffer->GetAvailableSize();
|
|
m_uAllocatedSize =
|
|
currentBuffer->GetAllocatedSize() - m_baseBufferOffset;
|
|
}
|
|
else
|
|
{
|
|
m_baseBufferOffset = 0;
|
|
m_uAllocatedSize = 0;
|
|
}
|
|
|
|
m_currentBufferOffset = 0;
|
|
m_currentBaseOffset = m_baseBufferOffset;
|
|
|
|
m_availableHighWaterMark = 0;
|
|
m_availableStartOffset = m_baseBufferOffset;
|
|
m_availableBufferOffset = 0;
|
|
m_lastAvailableBuffer = m_bufferList->GetHead();
|
|
}
|
|
|
|
RChannelWriterBuffer::~RChannelWriterBuffer()
|
|
{
|
|
}
|
|
|
|
void* RChannelWriterBuffer::GetDataAddress(Size_t uOffset,
|
|
Size_t *puSize,
|
|
Size_t *puPriorSize)
|
|
{
|
|
if (m_bufferList->IsEmpty())
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
LogAssert(uOffset >= m_currentBufferOffset);
|
|
|
|
Size_t offsetInAvailable = uOffset - m_currentBufferOffset;
|
|
Size_t offsetInBuffer = offsetInAvailable + m_currentBaseOffset;
|
|
|
|
DryadFixedMemoryBuffer* buffer =
|
|
m_bufferList->CastOut(m_bufferList->GetTail());
|
|
void* dataAddress =
|
|
buffer->GetDataAddress(offsetInBuffer, puSize, puPriorSize);
|
|
|
|
if (puPriorSize != NULL && *puPriorSize > offsetInAvailable)
|
|
{
|
|
*puPriorSize = offsetInAvailable;
|
|
}
|
|
|
|
return dataAddress;
|
|
}
|
|
}
|
|
|
|
void RChannelWriterBuffer::IncreaseAllocatedSize(Size_t uSize)
|
|
{
|
|
while (m_uAllocatedSize < uSize)
|
|
{
|
|
DryadFixedMemoryBuffer* newBuffer =
|
|
m_bufferProvider->GetNextWriteBuffer();
|
|
m_bufferList->InsertAsTail(m_bufferList->CastIn(newBuffer));
|
|
m_currentBufferOffset = m_uAllocatedSize;
|
|
m_uAllocatedSize += newBuffer->GetAllocatedSize();
|
|
}
|
|
|
|
/* this is zero for all but (optionally) the first buffer in the
|
|
list */
|
|
m_currentBaseOffset = 0;
|
|
}
|
|
|
|
void RChannelWriterBuffer::InternalSetAvailableSize(Size_t uSize)
|
|
{
|
|
DrMemoryBuffer::InternalSetAvailableSize(uSize);
|
|
|
|
LogAssert(uSize >= m_availableHighWaterMark);
|
|
|
|
if (m_lastAvailableBuffer == NULL)
|
|
{
|
|
LogAssert(m_availableBufferOffset == 0);
|
|
LogAssert(m_availableHighWaterMark == 0);
|
|
LogAssert(m_availableStartOffset == m_baseBufferOffset);
|
|
|
|
if (m_bufferList->IsEmpty())
|
|
{
|
|
LogAssert(uSize == 0);
|
|
return;
|
|
}
|
|
|
|
m_lastAvailableBuffer = m_bufferList->GetHead();
|
|
}
|
|
|
|
DrBListEntry* listEntry = m_lastAvailableBuffer;
|
|
if (listEntry == NULL)
|
|
{
|
|
listEntry = m_bufferList->GetHead();
|
|
LogAssert(listEntry != NULL);
|
|
}
|
|
|
|
do
|
|
{
|
|
DryadFixedMemoryBuffer* b = m_bufferList->CastOut(listEntry);
|
|
listEntry = m_bufferList->GetNext(listEntry);
|
|
|
|
if (listEntry == NULL)
|
|
{
|
|
LogAssert(uSize >= m_availableBufferOffset);
|
|
Size_t thisAvailable = uSize - m_availableBufferOffset;
|
|
|
|
LogAssert(m_availableStartOffset + thisAvailable <=
|
|
b->GetAllocatedSize());
|
|
b->SetAvailableSize(m_availableStartOffset + thisAvailable);
|
|
}
|
|
else
|
|
{
|
|
b->SetAvailableSize(b->GetAllocatedSize());
|
|
m_availableBufferOffset +=
|
|
b->GetAllocatedSize() - m_availableStartOffset;
|
|
LogAssert(m_availableBufferOffset < uSize);
|
|
m_lastAvailableBuffer = listEntry;
|
|
m_availableStartOffset = 0;
|
|
}
|
|
} while (listEntry != NULL);
|
|
|
|
m_availableHighWaterMark = uSize;
|
|
}
|
|
|
|
ChannelMemoryBufferWriter::
|
|
ChannelMemoryBufferWriter(DrMemoryBuffer* writeBuffer,
|
|
DryadFixedBufferList* bufferList) :
|
|
DrMemoryBufferWriter(writeBuffer)
|
|
{
|
|
m_bufferList = bufferList;
|
|
|
|
if (m_bufferList->IsEmpty())
|
|
{
|
|
m_initialBoundary = 0;
|
|
}
|
|
else
|
|
{
|
|
LogAssert(m_bufferList->CountLinks() == 1);
|
|
DryadFixedMemoryBuffer* buffer =
|
|
m_bufferList->CastOut(m_bufferList->GetHead());
|
|
m_initialBoundary = buffer->GetAvailableSize();
|
|
LogAssert(m_initialBoundary < buffer->GetAllocatedSize());
|
|
}
|
|
|
|
m_lastRecordBoundary = 0;
|
|
}
|
|
|
|
bool ChannelMemoryBufferWriter::MarkRecordBoundary()
|
|
{
|
|
if (m_bufferList->IsEmpty())
|
|
{
|
|
LogAssert(m_initialBoundary == 0);
|
|
LogAssert(m_lastRecordBoundary == 0);
|
|
return false;
|
|
}
|
|
else if (m_bufferList->CountLinks() == 1)
|
|
{
|
|
DryadFixedMemoryBuffer* buffer =
|
|
m_bufferList->CastOut(m_bufferList->GetHead());
|
|
Size_t offset = GetBufferOffset();
|
|
Size_t allocated = buffer->GetAllocatedSize();
|
|
|
|
if (m_initialBoundary + offset >= allocated)
|
|
{
|
|
DrError errTmp = FlushMemoryWriter();
|
|
// sammck: should this assert here or return an error
|
|
LogAssert(errTmp == DrError_OK);
|
|
}
|
|
|
|
Size_t boundary = buffer->GetAvailableSize();
|
|
if (boundary == allocated)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
m_lastRecordBoundary = offset;
|
|
LogAssert(m_initialBoundary + m_lastRecordBoundary < allocated);
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Size_t ChannelMemoryBufferWriter::GetLastRecordBoundary()
|
|
{
|
|
return m_initialBoundary + m_lastRecordBoundary;
|
|
}
|
|
|