gwenhywfar  4.7.0beta
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) {
45 
47 
48  me->memCache=memCache;
49  me->id=id;
50  me->dataPtr=dataPtr;
51  me->dataLen=dataLen;
52  me->isValid=1;
53 
54  /* update memcache */
55  me->memCache->currentCacheEntries++;
56  me->memCache->currentCacheMemory+=me->dataLen;
57 
58  return me;
59 }
60 
61 
62 
64  if (me) {
65  assert(me->useCounter==0);
66  assert(me->memCache);
67 
68  /* update memcache */
69  me->memCache->currentCacheEntries--;
70  me->memCache->currentCacheMemory-=me->dataLen;
71 
72  if (me->dataPtr && me->dataLen)
73  free(me->dataPtr);
74 
75  GWEN_FREE_OBJECT(me);
76  }
77 }
78 
79 
80 
82  assert(me);
83  return me->useCounter;
84 }
85 
86 
87 
89  assert(me);
90  return me->unusedSince;
91 }
92 
93 
94 
96  assert(me);
97  return me->id;
98 }
99 
100 
101 
103  assert(me);
104  return me->dataPtr;
105 }
106 
107 
108 
110  assert(me);
111  return me->dataLen;
112 }
113 
114 
115 
117  int rv;
118 
119  assert(me);
120  rv=GWEN_MemCache_Lock(me->memCache);
121  if (rv) {
122  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
123  assert(0);
124  }
125  me->useCounter++;
126  GWEN_MemCache_Unlock(me->memCache);
127 }
128 
129 
130 
132  int rv;
133 
134  assert(me);
135  rv=GWEN_MemCache_Lock(me->memCache);
136  if (rv) {
137  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
138  assert(0);
139  }
140  if (me->useCounter>0) {
141  me->useCounter--;
142  if (me->useCounter==0) {
143  if (!(me->isValid)) {
145  }
146  else
147  me->unusedSince=time(0);
148  }
149  }
150  else {
151  DBG_ERROR(GWEN_LOGDOMAIN, "Use counter < 1, aborting");
152  GWEN_MemCache_Unlock(me->memCache);
153  assert(me->useCounter>0);
154  }
155  GWEN_MemCache_Unlock(me->memCache);
156 }
157 
158 
159 
160 
161 
162 
163 
164 GWEN_MEMCACHE *GWEN_MemCache_new(size_t maxCacheMemory,
165  uint32_t maxCacheEntries) {
166  GWEN_MEMCACHE *mc;
167 
169  mc->mutex=GWEN_Mutex_new();
170  mc->idMap=GWEN_MemCacheEntry_IdMap_new(GWEN_IdMapAlgo_Hex4);
171  mc->maxCacheMemory=maxCacheMemory;
172  mc->maxCacheEntries=maxCacheEntries;
173 
174  return mc;
175 }
176 
177 
178 
180  if (mc) {
181  GWEN_MemCacheEntry_IdMap_free(mc->idMap);
182  GWEN_Mutex_free(mc->mutex);
183  GWEN_FREE_OBJECT(mc);
184  }
185 }
186 
187 
188 
190  uint32_t id) {
192 
193  assert(mc);
194  GWEN_MemCache_Lock(mc);
195  me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
196  if (me) {
197  /* we can't call GWEN_MemCache_BeginUse() here because of the mutex */
198  me->useCounter++;
199  }
201 
202  return me;
203 }
204 
205 
206 
208  uint32_t id) {
210 
211  assert(mc);
212  GWEN_MemCache_Lock(mc);
213  me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
214  if (me) {
215  me->isValid=0;
216  GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
217  if (me->useCounter==0)
219  }
221 }
222 
223 
224 
226  size_t neededSize) {
227  assert(mc);
228 
229  /* release unused entries until there is enough memory */
230  while(neededSize) {
231  GWEN_MEMCACHE_ENTRY *oldestEntry;
232  GWEN_IDMAP_RESULT res;
233  uint32_t currentId;
234 
235  /* get oldest entry */
236  oldestEntry=NULL;
237  res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
238  while(res==GWEN_IdMapResult_Ok) {
240 
241  me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
242  if (me) {
243  if (me->isValid && me->useCounter==0) {
244  if (oldestEntry==NULL)
245  oldestEntry=me;
246  else {
247  if (me->unusedSince<oldestEntry->unusedSince)
248  oldestEntry=me;
249  }
250  }
251  }
252  res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &currentId);
253  }
254 
255  if (oldestEntry==NULL)
256  /* no unused entry found */
257  break;
258 
259  /* subtract size of to-be-removed entry from needed size */
260  if (neededSize<oldestEntry->dataLen)
261  neededSize=0;
262  else
263  neededSize-=oldestEntry->dataLen;
264 
265  /* remove oldest entry (it is unused, so we also delete it here) */
266  GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, oldestEntry->id);
267  GWEN_MemCacheEntry_free(oldestEntry);
268  }
269 
270  return (neededSize==0)?0:GWEN_ERROR_MEMORY_FULL;
271 }
272 
273 
274 
276  uint32_t id,
277  void *dataPtr,
278  size_t dataLen) {
280 
281  assert(mc);
282  GWEN_MemCache_Lock(mc);
283 
284  /* invalidate possibly existing entry in any case */
285  me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
286  if (me) {
287  me->isValid=0;
288  GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
289  if (me->useCounter==0)
291  }
292 
293  /* check for limits: entry count */
294  if (mc->currentCacheEntries>=mc->maxCacheEntries) {
295  int rv;
296 
297  /* release unused entries (at least 1 byte) */
298  rv=GWEN_MemCache__MakeRoom(mc, 1);
299  if (rv) {
300  DBG_WARN(GWEN_LOGDOMAIN, "Too many entries in use");
302  return NULL;
303  }
304  }
305 
306  /* check for limits: memory in use */
307  if ((mc->currentCacheMemory+dataLen)>=mc->maxCacheMemory) {
308  size_t diff;
309  int rv;
310 
311  diff=(mc->currentCacheMemory+dataLen)-mc->maxCacheMemory;
312  /* release unused entries */
313  rv=GWEN_MemCache__MakeRoom(mc, diff);
314  if (rv) {
315  DBG_WARN(GWEN_LOGDOMAIN, "Too much memory in use");
317  return NULL;
318  }
319  }
320 
321  /* create new entry */
322  me=GWEN_MemCacheEntry_new(mc, id, dataPtr, dataLen);
323  assert(me);
324  me->useCounter++;
325  GWEN_MemCacheEntry_IdMap_Insert(mc->idMap, id, me);
326 
328 
329  return me;
330 }
331 
332 
333 
335  uint32_t id, uint32_t mask) {
336  GWEN_IDMAP_RESULT res;
337  uint32_t currentId;
338 
339  assert(mc);
340  GWEN_MemCache_Lock(mc);
341 
342  res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
343  while(res==GWEN_IdMapResult_Ok) {
344  uint32_t nextId;
345 
346  nextId=currentId;
347  res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &nextId);
348  if ((currentId & mask)==id) {
350 
351  me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
352  if (me) {
353  me->isValid=0;
354  GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, currentId);
355  if (me->useCounter==0)
357  }
358 
359  }
360  currentId=nextId;
361  }
362 
364 }
365 
366 
367 
369  assert(mc);
370  GWEN_MemCache_PurgeEntries(mc, 0, 0);
371 }
372 
373 
374 
376  assert(mc);
377  return GWEN_Mutex_Lock(mc->mutex);
378 }
379 
380 
381 
383  assert(mc);
384  return GWEN_Mutex_Unlock(mc->mutex);
385 }
386 
387 
388 
389 
390 
391 
392 
393