* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
* Distributed under the terms of the MIT License.
*/
#include <package/hpkg/BlockBufferPoolImpl.h>
#include <algorithm>
#include <new>
#include <AutoLocker.h>
#include <package/hpkg/PoolBuffer.h>
namespace BPackageKit {
namespace BHPKG {
namespace BPrivate {
BlockBufferPoolImpl::BlockBufferPoolImpl(size_t blockSize,
uint32 maxCachedBlocks, BBufferPoolLockable* lockable)
:
fBlockSize(blockSize),
fMaxCachedBlocks(maxCachedBlocks),
fAllocatedBlocks(0),
fLockable(lockable)
{
}
BlockBufferPoolImpl::~BlockBufferPoolImpl()
{
while (PoolBuffer* block = fCachedBuffers.RemoveHead())
delete block;
while (PoolBuffer* block = fUnusedBuffers.RemoveHead())
delete block;
}
status_t
BlockBufferPoolImpl::Init()
{
return B_OK;
}
PoolBuffer*
BlockBufferPoolImpl::GetBuffer(size_t size, PoolBuffer** owner, bool* _newBuffer)
{
if (size > fBlockSize)
return _AllocateBuffer(size, owner, _newBuffer);
AutoLocker<BBufferPoolLockable> locker(fLockable);
if (owner != NULL && *owner != NULL) {
PoolBuffer* buffer = *owner;
fCachedBuffers.Remove(buffer);
if (_newBuffer != NULL)
*_newBuffer = false;
return buffer;
}
PoolBuffer* buffer = fUnusedBuffers.RemoveHead();
if (buffer != NULL) {
buffer->SetOwner(owner);
if (owner != NULL)
*owner = buffer;
if (_newBuffer != NULL)
*_newBuffer = true;
return buffer;
}
if (fAllocatedBlocks >= fMaxCachedBlocks) {
buffer = fCachedBuffers.RemoveHead();
if (buffer != NULL) {
buffer->SetCached(false);
*buffer->Owner() = NULL;
buffer->SetOwner(owner);
if (owner != NULL)
*owner = buffer;
if (_newBuffer != NULL)
*_newBuffer = true;
return buffer;
}
}
locker.Unlock();
return _AllocateBuffer(size, owner, _newBuffer);
}
void
BlockBufferPoolImpl::PutBufferAndCache(PoolBuffer** owner)
{
PoolBuffer* buffer = *owner;
if (buffer->Size() != fBlockSize) {
*owner = NULL;
delete buffer;
return;
}
AutoLocker<BBufferPoolLockable> locker(fLockable);
buffer->SetOwner(owner);
fCachedBuffers.Add(buffer);
buffer->SetCached(true);
if (fAllocatedBlocks > fMaxCachedBlocks) {
PoolBuffer* otherBuffer = fUnusedBuffers.RemoveHead();
if (otherBuffer == NULL) {
otherBuffer = fCachedBuffers.RemoveHead();
*otherBuffer->Owner() = NULL;
otherBuffer->SetCached(false);
}
delete otherBuffer;
}
}
void
BlockBufferPoolImpl::PutBuffer(PoolBuffer** owner)
{
AutoLocker<BBufferPoolLockable> locker(fLockable);
PoolBuffer* buffer = *owner;
if (buffer == NULL)
return;
if (buffer->IsCached()) {
fCachedBuffers.Remove(buffer);
buffer->SetCached(false);
}
buffer->SetOwner(NULL);
*owner = NULL;
if (buffer->Size() == fBlockSize && fAllocatedBlocks < fMaxCachedBlocks)
fUnusedBuffers.Add(buffer);
else
delete buffer;
}
PoolBuffer*
BlockBufferPoolImpl::_AllocateBuffer(size_t size, PoolBuffer** owner,
bool* _newBuffer)
{
PoolBuffer* buffer = new(std::nothrow) PoolBuffer(
std::max(size, fBlockSize));
if (buffer == NULL || buffer->Buffer() == NULL) {
delete buffer;
return NULL;
}
buffer->SetOwner(owner);
if (_newBuffer != NULL)
*_newBuffer = true;
AutoLocker<BBufferPoolLockable> locker(fLockable);
fAllocatedBlocks++;
if (owner != NULL)
*owner = buffer;
return buffer;
}
}
}
}