1 /***************************************************************************
2 begin : Mon Jul 14 2008
3 copyright : (C) 2008 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * *
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 * *
23 ***************************************************************************/
24
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include "memcache_p.h"
31 #include <gwenhywfar/misc.h>
32 #include <gwenhywfar/debug.h>
33
34
35
GWEN_IDMAP_FUNCTIONS(GWEN_MEMCACHE_ENTRY,GWEN_MemCacheEntry)36 GWEN_IDMAP_FUNCTIONS(GWEN_MEMCACHE_ENTRY, GWEN_MemCacheEntry)
37
38
39
40 GWEN_MEMCACHE_ENTRY *GWEN_MemCacheEntry_new(GWEN_MEMCACHE *memCache,
41 uint32_t id,
42 void *dataPtr,
43 size_t dataLen)
44 {
45 GWEN_MEMCACHE_ENTRY *me;
46
47 GWEN_NEW_OBJECT(GWEN_MEMCACHE_ENTRY, me);
48
49 me->memCache=memCache;
50 me->id=id;
51 me->dataPtr=dataPtr;
52 me->dataLen=dataLen;
53 me->isValid=1;
54
55 /* update memcache */
56 me->memCache->currentCacheEntries++;
57 me->memCache->currentCacheMemory+=me->dataLen;
58
59 return me;
60 }
61
62
63
GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY * me)64 void GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY *me)
65 {
66 if (me) {
67 assert(me->useCounter==0);
68 assert(me->memCache);
69
70 /* update memcache */
71 me->memCache->currentCacheEntries--;
72 me->memCache->currentCacheMemory-=me->dataLen;
73
74 if (me->dataPtr && me->dataLen)
75 free(me->dataPtr);
76
77 GWEN_FREE_OBJECT(me);
78 }
79 }
80
81
82
GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY * me)83 int GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY *me)
84 {
85 assert(me);
86 return me->useCounter;
87 }
88
89
90
GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY * me)91 time_t GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY *me)
92 {
93 assert(me);
94 return me->unusedSince;
95 }
96
97
98
GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY * me)99 uint32_t GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY *me)
100 {
101 assert(me);
102 return me->id;
103 }
104
105
106
GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY * me)107 void *GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY *me)
108 {
109 assert(me);
110 return me->dataPtr;
111 }
112
113
114
GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY * me)115 size_t GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY *me)
116 {
117 assert(me);
118 return me->dataLen;
119 }
120
121
122
GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY * me)123 void GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY *me)
124 {
125 int rv;
126
127 assert(me);
128 rv=GWEN_MemCache_Lock(me->memCache);
129 if (rv) {
130 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
131 assert(0);
132 }
133 me->useCounter++;
134 GWEN_MemCache_Unlock(me->memCache);
135 }
136
137
138
GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY * me)139 void GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY *me)
140 {
141 int rv;
142
143 assert(me);
144 rv=GWEN_MemCache_Lock(me->memCache);
145 if (rv) {
146 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
147 assert(0);
148 }
149 if (me->useCounter>0) {
150 me->useCounter--;
151 if (me->useCounter==0) {
152 if (!(me->isValid)) {
153 GWEN_MemCacheEntry_free(me);
154 }
155 else
156 me->unusedSince=time(0);
157 }
158 }
159 else {
160 DBG_ERROR(GWEN_LOGDOMAIN, "Use counter < 1, aborting");
161 GWEN_MemCache_Unlock(me->memCache);
162 assert(me->useCounter>0);
163 }
164 GWEN_MemCache_Unlock(me->memCache);
165 }
166
167
168
169
170
171
172
GWEN_MemCache_new(size_t maxCacheMemory,uint32_t maxCacheEntries)173 GWEN_MEMCACHE *GWEN_MemCache_new(size_t maxCacheMemory,
174 uint32_t maxCacheEntries)
175 {
176 GWEN_MEMCACHE *mc;
177
178 GWEN_NEW_OBJECT(GWEN_MEMCACHE, mc);
179 mc->mutex=GWEN_Mutex_new();
180 mc->idMap=GWEN_MemCacheEntry_IdMap_new(GWEN_IdMapAlgo_Hex4);
181 mc->maxCacheMemory=maxCacheMemory;
182 mc->maxCacheEntries=maxCacheEntries;
183
184 return mc;
185 }
186
187
188
GWEN_MemCache_free(GWEN_MEMCACHE * mc)189 void GWEN_MemCache_free(GWEN_MEMCACHE *mc)
190 {
191 if (mc) {
192 GWEN_MemCacheEntry_IdMap_free(mc->idMap);
193 GWEN_Mutex_free(mc->mutex);
194 GWEN_FREE_OBJECT(mc);
195 }
196 }
197
198
199
GWEN_MemCache_FindEntry(GWEN_MEMCACHE * mc,uint32_t id)200 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_FindEntry(GWEN_MEMCACHE *mc,
201 uint32_t id)
202 {
203 GWEN_MEMCACHE_ENTRY *me;
204
205 assert(mc);
206 GWEN_MemCache_Lock(mc);
207 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
208 if (me) {
209 /* we can't call GWEN_MemCache_BeginUse() here because of the mutex */
210 me->useCounter++;
211 }
212 GWEN_MemCache_Unlock(mc);
213
214 return me;
215 }
216
217
218
GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE * mc,uint32_t id)219 void GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE *mc,
220 uint32_t id)
221 {
222 GWEN_MEMCACHE_ENTRY *me;
223
224 assert(mc);
225 GWEN_MemCache_Lock(mc);
226 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
227 if (me) {
228 me->isValid=0;
229 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
230 if (me->useCounter==0)
231 GWEN_MemCacheEntry_free(me);
232 }
233 GWEN_MemCache_Unlock(mc);
234 }
235
236
237
GWEN_MemCache__MakeRoom(GWEN_MEMCACHE * mc,size_t neededSize)238 int GWEN_MemCache__MakeRoom(GWEN_MEMCACHE *mc,
239 size_t neededSize)
240 {
241 assert(mc);
242
243 /* release unused entries until there is enough memory */
244 while (neededSize) {
245 GWEN_MEMCACHE_ENTRY *oldestEntry;
246 GWEN_IDMAP_RESULT res;
247 uint32_t currentId;
248
249 /* get oldest entry */
250 oldestEntry=NULL;
251 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, ¤tId);
252 while (res==GWEN_IdMapResult_Ok) {
253 GWEN_MEMCACHE_ENTRY *me;
254
255 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
256 if (me) {
257 if (me->isValid && me->useCounter==0) {
258 if (oldestEntry==NULL)
259 oldestEntry=me;
260 else {
261 if (me->unusedSince<oldestEntry->unusedSince)
262 oldestEntry=me;
263 }
264 }
265 }
266 res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, ¤tId);
267 }
268
269 if (oldestEntry==NULL)
270 /* no unused entry found */
271 break;
272
273 /* subtract size of to-be-removed entry from needed size */
274 if (neededSize<oldestEntry->dataLen)
275 neededSize=0;
276 else
277 neededSize-=oldestEntry->dataLen;
278
279 /* remove oldest entry (it is unused, so we also delete it here) */
280 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, oldestEntry->id);
281 GWEN_MemCacheEntry_free(oldestEntry);
282 }
283
284 return (neededSize==0)?0:GWEN_ERROR_MEMORY_FULL;
285 }
286
287
288
GWEN_MemCache_CreateEntry(GWEN_MEMCACHE * mc,uint32_t id,void * dataPtr,size_t dataLen)289 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_CreateEntry(GWEN_MEMCACHE *mc,
290 uint32_t id,
291 void *dataPtr,
292 size_t dataLen)
293 {
294 GWEN_MEMCACHE_ENTRY *me;
295
296 assert(mc);
297 GWEN_MemCache_Lock(mc);
298
299 /* invalidate possibly existing entry in any case */
300 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
301 if (me) {
302 me->isValid=0;
303 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
304 if (me->useCounter==0)
305 GWEN_MemCacheEntry_free(me);
306 }
307
308 /* check for limits: entry count */
309 if (mc->currentCacheEntries>=mc->maxCacheEntries) {
310 int rv;
311
312 /* release unused entries (at least 1 byte) */
313 rv=GWEN_MemCache__MakeRoom(mc, 1);
314 if (rv) {
315 DBG_WARN(GWEN_LOGDOMAIN, "Too many entries in use");
316 GWEN_MemCache_Unlock(mc);
317 return NULL;
318 }
319 }
320
321 /* check for limits: memory in use */
322 if ((mc->currentCacheMemory+dataLen)>=mc->maxCacheMemory) {
323 size_t diff;
324 int rv;
325
326 diff=(mc->currentCacheMemory+dataLen)-mc->maxCacheMemory;
327 /* release unused entries */
328 rv=GWEN_MemCache__MakeRoom(mc, diff);
329 if (rv) {
330 DBG_WARN(GWEN_LOGDOMAIN, "Too much memory in use");
331 GWEN_MemCache_Unlock(mc);
332 return NULL;
333 }
334 }
335
336 /* create new entry */
337 me=GWEN_MemCacheEntry_new(mc, id, dataPtr, dataLen);
338 assert(me);
339 me->useCounter++;
340 GWEN_MemCacheEntry_IdMap_Insert(mc->idMap, id, me);
341
342 GWEN_MemCache_Unlock(mc);
343
344 return me;
345 }
346
347
348
GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE * mc,uint32_t id,uint32_t mask)349 void GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE *mc,
350 uint32_t id, uint32_t mask)
351 {
352 GWEN_IDMAP_RESULT res;
353 uint32_t currentId;
354
355 assert(mc);
356 GWEN_MemCache_Lock(mc);
357
358 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, ¤tId);
359 while (res==GWEN_IdMapResult_Ok) {
360 uint32_t nextId;
361
362 nextId=currentId;
363 res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &nextId);
364 if ((currentId & mask)==id) {
365 GWEN_MEMCACHE_ENTRY *me;
366
367 me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
368 if (me) {
369 me->isValid=0;
370 GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, currentId);
371 if (me->useCounter==0)
372 GWEN_MemCacheEntry_free(me);
373 }
374
375 }
376 currentId=nextId;
377 }
378
379 GWEN_MemCache_Unlock(mc);
380 }
381
382
383
GWEN_MemCache_Purge(GWEN_MEMCACHE * mc)384 void GWEN_MemCache_Purge(GWEN_MEMCACHE *mc)
385 {
386 assert(mc);
387 GWEN_MemCache_PurgeEntries(mc, 0, 0);
388 }
389
390
391
GWEN_MemCache_Lock(GWEN_MEMCACHE * mc)392 int GWEN_MemCache_Lock(GWEN_MEMCACHE *mc)
393 {
394 assert(mc);
395 return GWEN_Mutex_Lock(mc->mutex);
396 }
397
398
399
GWEN_MemCache_Unlock(GWEN_MEMCACHE * mc)400 int GWEN_MemCache_Unlock(GWEN_MEMCACHE *mc)
401 {
402 assert(mc);
403 return GWEN_Mutex_Unlock(mc->mutex);
404 }
405
406
407
408
409
410
411
412
413