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 
36 GWEN_IDMAP_FUNCTIONS(GWEN_MEMCACHE_ENTRY, GWEN_MemCacheEntry)
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 
77  GWEN_FREE_OBJECT(me);
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 
173 GWEN_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);
194  GWEN_FREE_OBJECT(mc);
195  }
196 }
197 
198 
199 
201  uint32_t id)
202 {
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  }
213 
214  return me;
215 }
216 
217 
218 
220  uint32_t id)
221 {
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)
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;
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, &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);
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)
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 {
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, &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);
387  GWEN_MemCache_PurgeEntries(mc, 0, 0);
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 
GWEN_IDMAP_RESULT
Definition: idmap.h:40
int GWEN_MemCache_Lock(GWEN_MEMCACHE *mc)
Definition: memcache.c:392
int GWEN_MemCache__MakeRoom(GWEN_MEMCACHE *mc, size_t neededSize)
Definition: memcache.c:238
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define NULL
Definition: binreloc.c:300
#define DBG_WARN(dbg_logger, format, args...)
Definition: debug.h:125
#define GWEN_LOGDOMAIN
Definition: logger.h:35
void GWEN_MemCache_Purge(GWEN_MEMCACHE *mc)
Definition: memcache.c:384
GWENHYWFAR_API int GWEN_Mutex_Lock(GWEN_MUTEX *mtx)
void GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:123
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
void GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE *mc, uint32_t id)
Definition: memcache.c:219
GWENHYWFAR_API GWEN_MUTEX * GWEN_Mutex_new(void)
struct GWEN_MEMCACHE_ENTRY GWEN_MEMCACHE_ENTRY
Definition: memcache.h:36
GWENHYWFAR_API int GWEN_Mutex_Unlock(GWEN_MUTEX *mtx)
void * GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:107
GWEN_MEMCACHE_ENTRY * GWEN_MemCache_FindEntry(GWEN_MEMCACHE *mc, uint32_t id)
Definition: memcache.c:200
uint32_t GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:99
void GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:139
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
GWENHYWFAR_API void GWEN_Mutex_free(GWEN_MUTEX *mtx)
void GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:64
void GWEN_MemCache_free(GWEN_MEMCACHE *mc)
Definition: memcache.c:189
int GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:83
time_t GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:91
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
struct GWEN_MEMCACHE GWEN_MEMCACHE
Definition: memcache.h:38
int GWEN_MemCache_Unlock(GWEN_MEMCACHE *mc)
Definition: memcache.c:400
GWEN_MEMCACHE_ENTRY * GWEN_MemCache_CreateEntry(GWEN_MEMCACHE *mc, uint32_t id, void *dataPtr, size_t dataLen)
Definition: memcache.c:289
size_t GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY *me)
Definition: memcache.c:115
GWEN_MEMCACHE * GWEN_MemCache_new(size_t maxCacheMemory, uint32_t maxCacheEntries)
Definition: memcache.c:173
GWEN_IDMAP_FUNCTIONS(GWEN_MULTICACHE_ENTRY, GWEN_MultiCache_Entry)
#define GWEN_ERROR_MEMORY_FULL
Definition: error.h:77
GWEN_MEMCACHE_ENTRY * GWEN_MemCacheEntry_new(GWEN_MEMCACHE *memCache, uint32_t id, void *dataPtr, size_t dataLen)
Definition: memcache.c:40
void GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE *mc, uint32_t id, uint32_t mask)
Definition: memcache.c:349