xref: /haiku/src/kits/package/hpkg/BlockBufferPoolImpl.cpp (revision 9f81ca838ce7b92b5689e57d3f86765db4705a7b)
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