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