xref: /haiku/src/kits/package/hpkg/BlockBufferPoolImpl.cpp (revision 13581b3d2a71545960b98fefebc5225b5bf29072)
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 
18 namespace BPackageKit {
19 
20 namespace BHPKG {
21 
22 namespace BPrivate {
23 
24 
25 // #pragma mark - BlockBufferPoolImpl
26 
27 
28 BlockBufferPoolImpl::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 
39 BlockBufferPoolImpl::~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 
50 status_t
51 BlockBufferPoolImpl::Init()
52 {
53 	return B_OK;
54 }
55 
56 
57 PoolBuffer*
58 BlockBufferPoolImpl::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 
110 void
111 BlockBufferPoolImpl::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 
143 void
144 BlockBufferPoolImpl::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 
168 PoolBuffer*
169 BlockBufferPoolImpl::_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