gwenhywfar  4.3.1
memcache.c
Go to the documentation of this file.
00001 /***************************************************************************
00002     begin       : Mon Jul 14 2008
00003     copyright   : (C) 2008 by Martin Preuss
00004     email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *                                                                         *
00008  *   This library is free software; you can redistribute it and/or         *
00009  *   modify it under the terms of the GNU Lesser General Public            *
00010  *   License as published by the Free Software Foundation; either          *
00011  *   version 2.1 of the License, or (at your option) any later version.    *
00012  *                                                                         *
00013  *   This library is distributed in the hope that it will be useful,       *
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00016  *   Lesser General Public License for more details.                       *
00017  *                                                                         *
00018  *   You should have received a copy of the GNU Lesser General Public      *
00019  *   License along with this library; if not, write to the Free Software   *
00020  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
00021  *   MA  02111-1307  USA                                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 
00030 #include "memcache_p.h"
00031 #include <gwenhywfar/misc.h>
00032 #include <gwenhywfar/debug.h>
00033 
00034 
00035 
00036 GWEN_IDMAP_FUNCTIONS(GWEN_MEMCACHE_ENTRY, GWEN_MemCacheEntry)
00037 
00038 
00039 
00040 GWEN_MEMCACHE_ENTRY *GWEN_MemCacheEntry_new(GWEN_MEMCACHE *memCache,
00041                                             uint32_t id,
00042                                             void *dataPtr,
00043                                             size_t dataLen) {
00044   GWEN_MEMCACHE_ENTRY *me;
00045 
00046   GWEN_NEW_OBJECT(GWEN_MEMCACHE_ENTRY, me);
00047 
00048   me->memCache=memCache;
00049   me->id=id;
00050   me->dataPtr=dataPtr;
00051   me->dataLen=dataLen;
00052   me->isValid=1;
00053 
00054   /* update memcache */
00055   me->memCache->currentCacheEntries++;
00056   me->memCache->currentCacheMemory+=me->dataLen;
00057 
00058   return me;
00059 }
00060 
00061 
00062 
00063 void GWEN_MemCacheEntry_free(GWEN_MEMCACHE_ENTRY *me) {
00064   if (me) {
00065     assert(me->useCounter==0);
00066     assert(me->memCache);
00067 
00068   /* update memcache */
00069     me->memCache->currentCacheEntries--;
00070     me->memCache->currentCacheMemory-=me->dataLen;
00071 
00072     if (me->dataPtr && me->dataLen)
00073       free(me->dataPtr);
00074 
00075     GWEN_FREE_OBJECT(me);
00076   }
00077 }
00078 
00079 
00080 
00081 int GWEN_MemCacheEntry_GetUseCounter(const GWEN_MEMCACHE_ENTRY *me) {
00082   assert(me);
00083   return me->useCounter;
00084 }
00085 
00086 
00087 
00088 time_t GWEN_MemCacheEntry_GetUnusedSince(GWEN_MEMCACHE_ENTRY *me) {
00089   assert(me);
00090   return me->unusedSince;
00091 }
00092 
00093 
00094 
00095 uint32_t GWEN_MemCacheEntry_GetId(GWEN_MEMCACHE_ENTRY *me) {
00096   assert(me);
00097   return me->id;
00098 }
00099 
00100 
00101 
00102 void *GWEN_MemCacheEntry_GetDataPtr(GWEN_MEMCACHE_ENTRY *me) {
00103   assert(me);
00104   return me->dataPtr;
00105 }
00106 
00107 
00108 
00109 size_t GWEN_MemCacheEntry_GetDataLen(GWEN_MEMCACHE_ENTRY *me) {
00110   assert(me);
00111   return me->dataLen;
00112 }
00113 
00114 
00115 
00116 void GWEN_MemCacheEntry_BeginUse(GWEN_MEMCACHE_ENTRY *me) {
00117   int rv;
00118 
00119   assert(me);
00120   rv=GWEN_MemCache_Lock(me->memCache);
00121   if (rv) {
00122     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00123     assert(0);
00124   }
00125   me->useCounter++;
00126   GWEN_MemCache_Unlock(me->memCache);
00127 }
00128 
00129 
00130 
00131 void GWEN_MemCacheEntry_EndUse(GWEN_MEMCACHE_ENTRY *me) {
00132   int rv;
00133 
00134   assert(me);
00135   rv=GWEN_MemCache_Lock(me->memCache);
00136   if (rv) {
00137     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00138     assert(0);
00139   }
00140   if (me->useCounter>0) {
00141     me->useCounter--;
00142     if (me->useCounter==0) {
00143       if (!(me->isValid)) {
00144         GWEN_MemCacheEntry_free(me);
00145       }
00146       else
00147         me->unusedSince=time(0);
00148     }
00149   }
00150   else {
00151     DBG_ERROR(GWEN_LOGDOMAIN, "Use counter < 1, aborting");
00152     GWEN_MemCache_Unlock(me->memCache);
00153     assert(me->useCounter>0);
00154   }
00155   GWEN_MemCache_Unlock(me->memCache);
00156 }
00157 
00158 
00159 
00160 
00161 
00162 
00163 
00164 GWEN_MEMCACHE *GWEN_MemCache_new(size_t maxCacheMemory,
00165                                  uint32_t maxCacheEntries) {
00166   GWEN_MEMCACHE *mc;
00167 
00168   GWEN_NEW_OBJECT(GWEN_MEMCACHE, mc);
00169   mc->mutex=GWEN_Mutex_new();
00170   mc->idMap=GWEN_MemCacheEntry_IdMap_new(GWEN_IdMapAlgo_Hex4);
00171   mc->maxCacheMemory=maxCacheMemory;
00172   mc->maxCacheEntries=maxCacheEntries;
00173 
00174   return mc;
00175 }
00176 
00177 
00178 
00179 void GWEN_MemCache_free(GWEN_MEMCACHE *mc) {
00180   if (mc) {
00181     GWEN_MemCacheEntry_IdMap_free(mc->idMap);
00182     GWEN_Mutex_free(mc->mutex);
00183     GWEN_FREE_OBJECT(mc);
00184   }
00185 }
00186 
00187 
00188 
00189 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_FindEntry(GWEN_MEMCACHE *mc,
00190                                              uint32_t id) {
00191   GWEN_MEMCACHE_ENTRY *me;
00192 
00193   assert(mc);
00194   GWEN_MemCache_Lock(mc);
00195   me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
00196   if (me) {
00197     /* we can't call GWEN_MemCache_BeginUse() here because of the mutex */
00198     me->useCounter++;
00199   }
00200   GWEN_MemCache_Unlock(mc);
00201 
00202   return me;
00203 }
00204 
00205 
00206 
00207 void GWEN_MemCache_PurgeEntry(GWEN_MEMCACHE *mc,
00208                               uint32_t id) {
00209   GWEN_MEMCACHE_ENTRY *me;
00210 
00211   assert(mc);
00212   GWEN_MemCache_Lock(mc);
00213   me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
00214   if (me) {
00215     me->isValid=0;
00216     GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
00217     if (me->useCounter==0)
00218       GWEN_MemCacheEntry_free(me);
00219   }
00220   GWEN_MemCache_Unlock(mc);
00221 }
00222 
00223 
00224 
00225 int GWEN_MemCache__MakeRoom(GWEN_MEMCACHE *mc,
00226                             size_t neededSize) {
00227   assert(mc);
00228 
00229   /* release unused entries until there is enough memory */
00230   while(neededSize) {
00231     GWEN_MEMCACHE_ENTRY *oldestEntry;
00232     GWEN_IDMAP_RESULT res;
00233     uint32_t currentId;
00234 
00235     /* get oldest entry */
00236     oldestEntry=NULL;
00237     res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
00238     while(res==GWEN_IdMapResult_Ok) {
00239       GWEN_MEMCACHE_ENTRY *me;
00240 
00241       me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
00242       if (me) {
00243         if (me->isValid && me->useCounter==0) {
00244           if (oldestEntry==NULL)
00245             oldestEntry=me;
00246           else {
00247             if (me->unusedSince<oldestEntry->unusedSince)
00248               oldestEntry=me;
00249           }
00250         }
00251       }
00252       res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &currentId);
00253     }
00254 
00255     if (oldestEntry==NULL)
00256       /* no unused entry found */
00257       break;
00258 
00259     /* subtract size of to-be-removed entry from needed size */
00260     if (neededSize<oldestEntry->dataLen)
00261       neededSize=0;
00262     else
00263       neededSize-=oldestEntry->dataLen;
00264 
00265     /* remove oldest entry (it is unused, so we also delete it here) */
00266     GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, oldestEntry->id);
00267     GWEN_MemCacheEntry_free(oldestEntry);
00268   }
00269 
00270   return (neededSize==0)?0:GWEN_ERROR_MEMORY_FULL;
00271 }
00272 
00273 
00274 
00275 GWEN_MEMCACHE_ENTRY *GWEN_MemCache_CreateEntry(GWEN_MEMCACHE *mc,
00276                                                uint32_t id,
00277                                                void *dataPtr,
00278                                                size_t dataLen) {
00279   GWEN_MEMCACHE_ENTRY *me;
00280 
00281   assert(mc);
00282   GWEN_MemCache_Lock(mc);
00283 
00284   /* invalidate possibly existing entry in any case */
00285   me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, id);
00286   if (me) {
00287     me->isValid=0;
00288     GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, id);
00289     if (me->useCounter==0)
00290       GWEN_MemCacheEntry_free(me);
00291   }
00292 
00293   /* check for limits: entry count */
00294   if (mc->currentCacheEntries>=mc->maxCacheEntries) {
00295     int rv;
00296 
00297     /* release unused entries (at least 1 byte) */
00298     rv=GWEN_MemCache__MakeRoom(mc, 1);
00299     if (rv) {
00300       DBG_WARN(GWEN_LOGDOMAIN, "Too many entries in use");
00301       GWEN_MemCache_Unlock(mc);
00302       return NULL;
00303     }
00304   }
00305 
00306   /* check for limits: memory in use */
00307   if ((mc->currentCacheMemory+dataLen)>=mc->maxCacheMemory) {
00308     size_t diff;
00309     int rv;
00310 
00311     diff=(mc->currentCacheMemory+dataLen)-mc->maxCacheMemory;
00312     /* release unused entries */
00313     rv=GWEN_MemCache__MakeRoom(mc, diff);
00314     if (rv) {
00315       DBG_WARN(GWEN_LOGDOMAIN, "Too much memory in use");
00316       GWEN_MemCache_Unlock(mc);
00317       return NULL;
00318     }
00319   }
00320 
00321   /* create new entry */
00322   me=GWEN_MemCacheEntry_new(mc, id, dataPtr, dataLen);
00323   assert(me);
00324   me->useCounter++;
00325   GWEN_MemCacheEntry_IdMap_Insert(mc->idMap, id, me);
00326 
00327   GWEN_MemCache_Unlock(mc);
00328 
00329   return me;
00330 }
00331 
00332 
00333 
00334 void GWEN_MemCache_PurgeEntries(GWEN_MEMCACHE *mc,
00335                                 uint32_t id, uint32_t mask) {
00336   GWEN_IDMAP_RESULT res;
00337   uint32_t currentId;
00338 
00339   assert(mc);
00340   GWEN_MemCache_Lock(mc);
00341 
00342   res=GWEN_MemCacheEntry_IdMap_GetFirst(mc->idMap, &currentId);
00343   while(res==GWEN_IdMapResult_Ok) {
00344     uint32_t nextId;
00345 
00346     nextId=currentId;
00347     res=GWEN_MemCacheEntry_IdMap_GetNext(mc->idMap, &nextId);
00348     if ((currentId & mask)==id) {
00349       GWEN_MEMCACHE_ENTRY *me;
00350 
00351       me=GWEN_MemCacheEntry_IdMap_Find(mc->idMap, currentId);
00352       if (me) {
00353         me->isValid=0;
00354         GWEN_MemCacheEntry_IdMap_Remove(mc->idMap, currentId);
00355         if (me->useCounter==0)
00356           GWEN_MemCacheEntry_free(me);
00357       }
00358 
00359     }
00360     currentId=nextId;
00361   }
00362 
00363   GWEN_MemCache_Unlock(mc);
00364 }
00365 
00366 
00367 
00368 void GWEN_MemCache_Purge(GWEN_MEMCACHE *mc) {
00369   assert(mc);
00370   GWEN_MemCache_PurgeEntries(mc, 0, 0);
00371 }
00372 
00373 
00374 
00375 int GWEN_MemCache_Lock(GWEN_MEMCACHE *mc) {
00376   assert(mc);
00377   return GWEN_Mutex_Lock(mc->mutex);
00378 }
00379 
00380 
00381 
00382 int GWEN_MemCache_Unlock(GWEN_MEMCACHE *mc) {
00383   assert(mc);
00384   return GWEN_Mutex_Unlock(mc->mutex);
00385 }
00386 
00387 
00388 
00389 
00390 
00391 
00392 
00393