gwenhywfar 5.10.1
memcache.c
Go to the documentation of this file.
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
37
38
39
41 uint32_t id,
42 void *dataPtr,
43 size_t dataLen)
44{
46
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
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
78 }
79}
80
81
82
84{
85 assert(me);
86 return me->useCounter;
87}
88
89
90
92{
93 assert(me);
94 return me->unusedSince;
95}
96
97
98
100{
101 assert(me);
102 return me->id;
103}
104
105
106
108{
109 assert(me);
110 return me->dataPtr;
111}
112
113
114
116{
117 assert(me);
118 return me->dataLen;
119}
120
121
122
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
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)) {
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
173GWEN_MEMCACHE *GWEN_MemCache_new(size_t maxCacheMemory,
174 uint32_t maxCacheEntries)
175{
176 GWEN_MEMCACHE *mc;
177
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
190{
191 if (mc) {
192 GWEN_MemCacheEntry_IdMap_free(mc->idMap);
193 GWEN_Mutex_free(mc->mutex);
195 }
196}
197
198
199
201 uint32_t id)
202{
204
205 assert(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 }
213
214 return me;
215}
216
217
218
220 uint32_t id)
221{
223
224 assert(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)
232 }
234}
235
236
237
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;
247 uint32_t currentId;
248
249 /* get oldest entry */
250 oldestEntry=NULL;
251 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
252 while (res==GWEN_IdMapResult_Ok) {
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, &currentId);
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
290 uint32_t id,
291 void *dataPtr,
292 size_t dataLen)
293{
295
296 assert(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)
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");
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");
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
343
344 return me;
345}
346
347
348
350 uint32_t id, uint32_t mask)
351{
353 uint32_t currentId;
354
355 assert(mc);
357
358 res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
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) {
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)
373 }
374
375 }
376 currentId=nextId;
377 }
378
380}
381
382
383
385{
386 assert(mc);
388}
389
390
391
393{
394 assert(mc);
395 return GWEN_Mutex_Lock(mc->mutex);
396}
397
398
399
401{
402 assert(mc);
403 return GWEN_Mutex_Unlock(mc->mutex);
404}
405
406
407
408
409
410
411
412
#define NULL
Definition: binreloc.c:300
#define DBG_WARN(dbg_logger, format, args...)
Definition: debug.h:125
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
#define GWEN_ERROR_MEMORY_FULL
Definition: error.h:77
GWEN_IDMAP_RESULT
Definition: idmap.h:40
@ GWEN_IdMapResult_Ok
Definition: idmap.h:41
@ GWEN_IdMapAlgo_Hex4
Definition: idmap.h:49
#define GWEN_IDMAP_FUNCTIONS(t, pr)
Definition: idmap.h:89
#define GWEN_LOGDOMAIN
Definition: logger.h:35
void * GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:107
GWEN_MEMCACHE_ENTRY * GWEN_MemCache_CreateEntry(GWEN_MEMCACHE *mc, uint32_t id, void *dataPtr, size_t dataLen)
Definition: memcache.c:289
GWEN_MEMCACHE * GWEN_MemCache_new(size_t maxCacheMemory, uint32_t maxCacheEntries)
Definition: memcache.c:173
void GWEN_MemCache_Purge(GWEN_MEMCACHE *mc)
Definition: memcache.c:384
void GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE *mc, uint32_t id, uint32_t mask)
Definition: memcache.c:349
int GWEN_MemCache_Unlock(GWEN_MEMCACHE *mc)
Definition: memcache.c:400
GWEN_MEMCACHE_ENTRY * GWEN_MemCache_FindEntry(GWEN_MEMCACHE *mc, uint32_t id)
Definition: memcache.c:200
void GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:123
void GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:139
int GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:83
int GWEN_MemCache_Lock(GWEN_MEMCACHE *mc)
Definition: memcache.c:392
GWEN_MEMCACHE_ENTRY * GWEN_MemCacheEntry_new(GWEN_MEMCACHE *memCache, uint32_t id, void *dataPtr, size_t dataLen)
Definition: memcache.c:40
void GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE *mc, uint32_t id)
Definition: memcache.c:219
size_t GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:115
uint32_t GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:99
void GWEN_MemCache_free(GWEN_MEMCACHE *mc)
Definition: memcache.c:189
void GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:64
time_t GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:91
int GWEN_MemCache__MakeRoom(GWEN_MEMCACHE *mc, size_t neededSize)
Definition: memcache.c:238
struct GWEN_MEMCACHE_ENTRY GWEN_MEMCACHE_ENTRY
Definition: memcache.h:36
struct GWEN_MEMCACHE GWEN_MEMCACHE
Definition: memcache.h:38
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
GWENHYWFAR_API int GWEN_Mutex_Unlock(GWEN_MUTEX *mtx)
GWENHYWFAR_API int GWEN_Mutex_Lock(GWEN_MUTEX *mtx)
GWENHYWFAR_API GWEN_MUTEX * GWEN_Mutex_new(void)
GWENHYWFAR_API void GWEN_Mutex_free(GWEN_MUTEX *mtx)