VirtualAllocBuffer.h

// VirtualAllocBuffer.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2011

#ifndef Ceda_cxMessage_VirtualAllocBuffer_H
#define Ceda_cxMessage_VirtualAllocBuffer_H

#include "cxMessage.h"
#include "Ceda/cxUtils/xvector.h"
#include <string.h>

/*
We use a single buffer allocated with VirtualAlloc to ensure it is a whole number of 
4kB pages. This seems appropriate given that async reads/writes will lock whole pages.

VirtualAlloc allows for a distinction between reserving and commiting memory. This is 
particularly beneficial on x64 platforms where we typically have much more virtual memory 
(8TB) than physical memory (maybe 8GB).

Under "normal circumstances" we reserve NormalReserveBufferSize, and of that only
commit NormalCommitBufferSize.  We would expect most messages to be smaller than 
NormalCommitBufferSize.  

Buffer management policy
------------------------

Parameters:
        // The following are all a multiple of the page size
        // We require NormalCommitBufferSize <= NormalReserveBufferSize <= MaxMsgSize
        ssize_t NormalCommitBufferSize;
        ssize_t NormalReserveBufferSize;
        ssize_t MaxMsgSize;
        
        ssize_t NumMsgsUntilBackToNormalBufferSize;
        
-   If a message is received with size in (NormalCommitBufferSize,NormalReserveBufferSize]
    we can easily commit additional pages if necessary without needing to reallocate memory 
    from scratch.
    
-   If a message is received with size in (NormalReserveBufferSize,MaxMsgSize] we can reallocate
    an entirely new buffer for that message.  In such cases we reserve and commit to a size
    rounded up to a multiple of the page size.
    
-   In general we keep track of what has been currently committed/reserved and where possible
    try to read the next message without any reallocations.
    
-   After NumMsgsUntilBackToNormalBufferSize messages have been received in a row that 
    don't exceed NormalCommitBufferSize the commit/reserve sizes are returned back to the 
    normal conditions. [or is a timeout more appropriate?]

IDEA: This policy can be implemented in a class VirtualAllocBuffer that represents the buffer 
for us.  It may also be possible for this class to make use of pooled memory buffers if that 
is appropriate.
*/

namespace ceda
{

/*
VirtualAllocBuffer is assumed to have the following functions:

    resize()
    size()
    data()
    ReallocAndMove()
*/

// for now...
typedef xvector<octet_t> VirtualAllocBuffer;

/*
Reallocate b to have size equal to newSize.
Copy the bytes in the range [offset, offset+count) back to position 0.
Used by both the MsgReader and MsgWriter
*/
inline void ReallocAndMove(VirtualAllocBuffer& b, ssize_t newSize, ssize_t offset, ssize_t count)
{
    cxAssert(0 <= newSize);
    cxAssert(0 <= offset);
    cxAssert(0 <= count);
    cxAssert(offset + count <= b.size());
    cxAssert(count <= newSize);
    
    VirtualAllocBuffer copy(newSize);
    memcpy(copy.data(), b.data()+offset, count);
    b.swap(copy);
}

} // namespace ceda

#endif // include guard