1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2011, Oliver Tappe <zooey@hirschkaefer.de>
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <package/hpkg/BlockBufferPoolImpl.h>
9
10#include <algorithm>
11#include <new>
12
13#include <AutoLocker.h>
14
15#include <package/hpkg/PoolBuffer.h>
16
17
18namespace BPackageKit {
19
20namespace BHPKG {
21
22namespace BPrivate {
23
24
25// #pragma mark - BlockBufferPoolImpl
26
27
28BlockBufferPoolImpl::BlockBufferPoolImpl(size_t blockSize,
29	uint32 maxCachedBlocks, BBufferPoolLockable* lockable)
30	:
31	fBlockSize(blockSize),
32	fMaxCachedBlocks(maxCachedBlocks),
33	fAllocatedBlocks(0),
34	fLockable(lockable)
35{
36}
37
38
39BlockBufferPoolImpl::~BlockBufferPoolImpl()
40{
41	// delete all cached blocks
42	while (PoolBuffer* block = fCachedBuffers.RemoveHead())
43		delete block;
44
45	while (PoolBuffer* block = fUnusedBuffers.RemoveHead())
46		delete block;
47}
48
49
50status_t
51BlockBufferPoolImpl::Init()
52{
53	return B_OK;
54}
55
56
57PoolBuffer*
58BlockBufferPoolImpl::GetBuffer(size_t size, PoolBuffer** owner, bool* _newBuffer)
59{
60	// for sizes greater than the block size, we always allocate a new buffer
61	if (size > fBlockSize)
62		return _AllocateBuffer(size, owner, _newBuffer);
63
64	AutoLocker<BBufferPoolLockable> locker(fLockable);
65
66	// if an owner is given and the buffer is still cached, return it
67	if (owner != NULL && *owner != NULL) {
68		PoolBuffer* buffer = *owner;
69		fCachedBuffers.Remove(buffer);
70
71		if (_newBuffer != NULL)
72			*_newBuffer = false;
73		return buffer;
74	}
75
76	// we need a new buffer -- try unused ones first
77	PoolBuffer* buffer = fUnusedBuffers.RemoveHead();
78	if (buffer != NULL) {
79		buffer->SetOwner(owner);
80
81		if (owner != NULL)
82			*owner = buffer;
83		if (_newBuffer != NULL)
84			*_newBuffer = true;
85		return buffer;
86	}
87
88	// if we have already hit the max block limit, steal a cached block
89	if (fAllocatedBlocks >= fMaxCachedBlocks) {
90		buffer = fCachedBuffers.RemoveHead();
91		if (buffer != NULL) {
92			buffer->SetCached(false);
93			*buffer->Owner() = NULL;
94			buffer->SetOwner(owner);
95
96			if (owner != NULL)
97				*owner = buffer;
98			if (_newBuffer != NULL)
99				*_newBuffer = true;
100			return buffer;
101		}
102	}
103
104	// allocate a new buffer
105	locker.Unlock();
106	return _AllocateBuffer(size, owner, _newBuffer);
107}
108
109
110void
111BlockBufferPoolImpl::PutBufferAndCache(PoolBuffer** owner)
112{
113	PoolBuffer* buffer = *owner;
114
115	// always delete buffers with non-standard size
116	if (buffer->Size() != fBlockSize) {
117		*owner = NULL;
118		delete buffer;
119		return;
120	}
121
122	AutoLocker<BBufferPoolLockable> locker(fLockable);
123
124	// queue the cached buffer
125	buffer->SetOwner(owner);
126	fCachedBuffers.Add(buffer);
127	buffer->SetCached(true);
128
129	if (fAllocatedBlocks > fMaxCachedBlocks) {
130		// We have exceeded the limit -- we need to free a buffer.
131		PoolBuffer* otherBuffer = fUnusedBuffers.RemoveHead();
132		if (otherBuffer == NULL) {
133			otherBuffer = fCachedBuffers.RemoveHead();
134			*otherBuffer->Owner() = NULL;
135			otherBuffer->SetCached(false);
136		}
137
138		delete otherBuffer;
139	}
140}
141
142
143void
144BlockBufferPoolImpl::PutBuffer(PoolBuffer** owner)
145{
146	AutoLocker<BBufferPoolLockable> locker(fLockable);
147
148	PoolBuffer* buffer = *owner;
149
150	if (buffer == NULL)
151		return;
152
153	if (buffer->IsCached()) {
154		fCachedBuffers.Remove(buffer);
155		buffer->SetCached(false);
156	}
157
158	buffer->SetOwner(NULL);
159	*owner = NULL;
160
161	if (buffer->Size() == fBlockSize && fAllocatedBlocks < fMaxCachedBlocks)
162		fUnusedBuffers.Add(buffer);
163	else
164		delete buffer;
165}
166
167
168PoolBuffer*
169BlockBufferPoolImpl::_AllocateBuffer(size_t size, PoolBuffer** owner,
170	bool* _newBuffer)
171{
172	PoolBuffer* buffer = new(std::nothrow) PoolBuffer(
173		std::max(size, fBlockSize));
174	if (buffer == NULL || buffer->Buffer() == NULL) {
175		delete buffer;
176		return NULL;
177	}
178
179	buffer->SetOwner(owner);
180
181	if (_newBuffer != NULL)
182		*_newBuffer = true;
183
184	AutoLocker<BBufferPoolLockable> locker(fLockable);
185	fAllocatedBlocks++;
186
187	if (owner != NULL)
188		*owner = buffer;
189
190	return buffer;
191}
192
193
194}	// namespace BPrivate
195
196}	// namespace BHPKG
197
198}	// namespace BPackageKit
199