mux/src/attrcache.cpp

Go to the documentation of this file.
00001 // svdocache.cpp -- Attribute caching module.
00002 //
00003 // $Id: attrcache.cpp,v 1.21 2006/01/07 06:26:07 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 static CHashFile hfAttributeFile;
00015 static bool cache_initted = false;
00016 
00017 static bool cache_redirected = false;
00018 #define N_TEMP_FILES 8
00019 static FILE *TempFiles[N_TEMP_FILES];
00020 
00021 CLinearTimeAbsolute cs_ltime;
00022 
00023 #pragma pack(1)
00024 typedef struct tagAttrRecord
00025 {
00026     Aname attrKey;
00027     char attrText[LBUF_SIZE];
00028 } ATTR_RECORD, *PATTR_RECORD;
00029 #pragma pack()
00030 
00031 static ATTR_RECORD TempRecord;
00032 
00033 typedef struct tagCacheEntryHeader
00034 {
00035     struct tagCacheEntryHeader *pPrevEntry;
00036     struct tagCacheEntryHeader *pNextEntry;
00037     Aname attrKey;
00038     unsigned int nSize;
00039 } CENT_HDR, *PCENT_HDR;
00040 
00041 static PCENT_HDR pCacheHead = 0;
00042 static PCENT_HDR pCacheTail = 0;
00043 static unsigned int CacheSize = 0;
00044 
00045 int cache_init(const char *game_dir_file, const char *game_pag_file,
00046     int nCachePages)
00047 {
00048     if (cache_initted)
00049     {
00050         return HF_OPEN_STATUS_ERROR;
00051     }
00052 
00053     int cc = hfAttributeFile.Open(game_dir_file, game_pag_file, nCachePages);
00054     if (cc != HF_OPEN_STATUS_ERROR)
00055     {
00056         // Mark caching system live
00057         //
00058         cache_initted = true;
00059         cs_ltime.GetUTC();
00060     }
00061     return cc;
00062 }
00063 
00064 void cache_redirect(void)
00065 {
00066     for (int i = 0; i < N_TEMP_FILES; i++)
00067     {
00068         char TempFileName[20];
00069         sprintf(TempFileName, "$convtemp.%d", i);
00070         TempFiles[i] = fopen(TempFileName, "wb+");
00071         mux_assert(TempFiles[i]);
00072         setvbuf(TempFiles[i], NULL, _IOFBF, 16384);
00073     }
00074     cache_redirected = true;
00075 }
00076 
00077 void cache_pass2(void)
00078 {
00079     ATTR_RECORD Record;
00080     cache_redirected = false;
00081     fprintf(stderr, "2nd Pass:\n");
00082     for (int i = 0; i < N_TEMP_FILES; i++)
00083     {
00084         fprintf(stderr, "File %d: ", i);
00085         long int li = fseek(TempFiles[i], 0, SEEK_SET);
00086         mux_assert(0L == li);
00087 
00088         int cnt = 1000;
00089         size_t nSize;
00090         for (;;)
00091         {
00092             size_t cc = fread(&nSize, 1, sizeof(nSize), TempFiles[i]);
00093             if (cc != sizeof(nSize))
00094             {
00095                 break;
00096             }
00097             cc = fread(&Record, 1, nSize, TempFiles[i]);
00098             mux_assert(cc == nSize);
00099             cache_put(&Record.attrKey, Record.attrText, nSize - sizeof(Aname));
00100             if (cnt-- == 0)
00101             {
00102                 fputc('.', stderr);
00103                 fflush(stderr);
00104                 cnt = 1000;
00105             }
00106         }
00107         fclose(TempFiles[i]);
00108         char TempFileName[20];
00109         sprintf(TempFileName, "$convtemp.%d", i);
00110         RemoveFile(TempFileName);
00111         fprintf(stderr, ENDLINE);
00112     }
00113 }
00114 
00115 void cache_close(void)
00116 {
00117     hfAttributeFile.CloseAll();
00118     cache_initted = false;
00119 }
00120 
00121 void cache_tick(void)
00122 {
00123     hfAttributeFile.Tick();
00124 }
00125 
00126 static void REMOVE_ENTRY(PCENT_HDR pEntry)
00127 {
00128     // How is X positioned?
00129     //
00130     if (pEntry == pCacheHead)
00131     {
00132         if (pEntry == pCacheTail)
00133         {
00134             // HEAD --> X --> 0
00135             //    0 <--  <-- TAIL
00136             //
00137             // ASSERT: pEntry->pNextEntry == 0;
00138             // ASSERT: pEntry->pPrevEntry == 0;
00139             //
00140             pCacheHead = pCacheTail = 0;
00141         }
00142         else
00143         {
00144             // HEAD  --> X --> Y --> 0
00145             //    0 <--   <--   <--  TAIL
00146             //
00147             // ASSERT: pEntry->pNextEntry != 0;
00148             // ASSERT: pEntry->pPrevEntry == 0;
00149             //
00150             pCacheHead = pEntry->pNextEntry;
00151             pCacheHead->pPrevEntry = 0;
00152             pEntry->pNextEntry = 0;
00153         }
00154     }
00155     else if (pEntry == pCacheTail)
00156     {
00157         // HEAD  --> Y --> X --> 0
00158         //    0 <--   <--   <-- TAIL
00159         //
00160         // ASSERT: pEntry->pNextEntry == 0;
00161         // ASSERT: pEntry->pPrevEntry != 0;
00162         //
00163         pCacheTail = pEntry->pPrevEntry;
00164         pCacheTail->pNextEntry = 0;
00165         pEntry->pPrevEntry = 0;
00166     }
00167     else
00168     {
00169         // HEAD  --> Y --> X --> Z --> 0
00170         //    0 <--   <--   <--   <-- TAIL
00171         //
00172         // ASSERT: pEntry->pNextEntry != 0;
00173         // ASSERT: pEntry->pNextEntry != 0;
00174         //
00175         pEntry->pNextEntry->pPrevEntry = pEntry->pPrevEntry;
00176         pEntry->pPrevEntry->pNextEntry = pEntry->pNextEntry;
00177         pEntry->pNextEntry = 0;
00178         pEntry->pPrevEntry = 0;
00179     }
00180 }
00181 
00182 static void ADD_ENTRY(PCENT_HDR pEntry)
00183 {
00184     if (pCacheHead)
00185     {
00186         pCacheHead->pPrevEntry = pEntry;
00187     }
00188     pEntry->pNextEntry = pCacheHead;
00189     pEntry->pPrevEntry = 0;
00190     pCacheHead = pEntry;
00191     if (!pCacheTail)
00192     {
00193         pCacheTail = pCacheHead;
00194     }
00195 }
00196 
00197 static void TrimCache(void)
00198 {
00199     // Check to see if the cache needs to be trimmed.
00200     //
00201     while (CacheSize > mudconf.max_cache_size)
00202     {
00203         // Blow something away.
00204         //
00205         PCENT_HDR pCacheEntry = pCacheTail;
00206         if (!pCacheEntry)
00207         {
00208             CacheSize = 0;
00209             break;
00210         }
00211 
00212         REMOVE_ENTRY(pCacheEntry);
00213         CacheSize -= pCacheEntry->nSize;
00214         hashdeleteLEN(&(pCacheEntry->attrKey), sizeof(Aname),
00215             &mudstate.acache_htab);
00216         MEMFREE(pCacheEntry);
00217         pCacheEntry = NULL;
00218     }
00219 }
00220 
00221 const char *cache_get(Aname *nam, int *pLen)
00222 {
00223     if (  nam == (Aname *) 0
00224        || !cache_initted)
00225     {
00226         *pLen = 0;
00227         return NULL;
00228     }
00229 
00230     PCENT_HDR pCacheEntry = NULL;
00231     if (!mudstate.bStandAlone)
00232     {
00233         // Check the cache, first.
00234         //
00235         pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00236             &mudstate.acache_htab);
00237         if (pCacheEntry)
00238         {
00239             // It was in the cache, so move this entry to the head of the queue.
00240             // and return a pointer to it.
00241             //
00242             REMOVE_ENTRY(pCacheEntry);
00243             ADD_ENTRY(pCacheEntry);
00244             if (sizeof(CENT_HDR) < pCacheEntry->nSize)
00245             {
00246                 *pLen = pCacheEntry->nSize - sizeof(CENT_HDR);
00247                 return (char *)(pCacheEntry+1);
00248             }
00249             else
00250             {
00251                 *pLen = 0;
00252                 return NULL;
00253             }
00254         }
00255     }
00256 
00257     UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum);
00258 
00259     HP_DIRINDEX iDir;
00260     iDir = hfAttributeFile.FindFirstKey(nHash);
00261     while (iDir != HF_FIND_END)
00262     {
00263         HP_HEAPLENGTH nRecord;
00264         hfAttributeFile.Copy(iDir, &nRecord, &TempRecord);
00265 
00266         if (  TempRecord.attrKey.attrnum == nam->attrnum
00267            && TempRecord.attrKey.object == nam->object)
00268         {
00269             int nLength = nRecord - sizeof(Aname);
00270             *pLen = nLength;
00271             if (!mudstate.bStandAlone)
00272             {
00273                 // Add this information to the cache.
00274                 //
00275                 pCacheEntry = (PCENT_HDR)MEMALLOC(sizeof(CENT_HDR)+nLength);
00276                 if (pCacheEntry)
00277                 {
00278                     pCacheEntry->attrKey = *nam;
00279                     pCacheEntry->nSize = nLength + sizeof(CENT_HDR);
00280                     CacheSize += pCacheEntry->nSize;
00281                     memcpy((char *)(pCacheEntry+1), TempRecord.attrText, nLength);
00282                     ADD_ENTRY(pCacheEntry);
00283                     hashaddLEN(nam, sizeof(Aname), pCacheEntry,
00284                         &mudstate.acache_htab);
00285 
00286                     TrimCache();
00287                 }
00288             }
00289             return TempRecord.attrText;
00290         }
00291         iDir = hfAttributeFile.FindNextKey(iDir, nHash);
00292     }
00293 
00294     // We didn't find that one.
00295     //
00296     if (!mudstate.bStandAlone)
00297     {
00298         // Add this information to the cache.
00299         //
00300         pCacheEntry = (PCENT_HDR)MEMALLOC(sizeof(CENT_HDR));
00301         if (pCacheEntry)
00302         {
00303             pCacheEntry->attrKey = *nam;
00304             pCacheEntry->nSize = sizeof(CENT_HDR);
00305             CacheSize += pCacheEntry->nSize;
00306             ADD_ENTRY(pCacheEntry);
00307             hashaddLEN(nam, sizeof(Aname), pCacheEntry,
00308                 &mudstate.acache_htab);
00309 
00310             TrimCache();
00311         }
00312     }
00313 
00314     *pLen = 0;
00315     return NULL;
00316 }
00317 
00318 
00319 // cache_put no longer frees the pointer.
00320 //
00321 bool cache_put(Aname *nam, const char *value, size_t len)
00322 {
00323     if (  !value
00324        || !nam
00325        || !cache_initted
00326        || len == 0)
00327     {
00328         return false;
00329     }
00330 #ifndef WIN32
00331     if (mudstate.write_protect)
00332     {
00333         Log.tinyprintf("cache_put((%d,%d), '%s', %u) while database is write-protected" ENDLINE,
00334             nam->object, nam->attrnum, value, len);
00335         return false;
00336     }
00337 #endif
00338 
00339     if (len > sizeof(TempRecord.attrText))
00340     {
00341         len = sizeof(TempRecord.attrText);
00342     }
00343 
00344     // Removal from DB.
00345     //
00346     UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum);
00347 
00348     if (cache_redirected)
00349     {
00350         TempRecord.attrKey = *nam;
00351         memcpy(TempRecord.attrText, value, len);
00352         TempRecord.attrText[len-1] = '\0';
00353 
00354         int iFile = (N_TEMP_FILES-1) & (nHash >> 29);
00355         size_t nSize = len+sizeof(Aname);
00356         fwrite(&nSize, 1, sizeof(nSize), TempFiles[iFile]);
00357         fwrite(&TempRecord, 1, nSize, TempFiles[iFile]);
00358         return true;
00359     }
00360 
00361     HP_DIRINDEX iDir = hfAttributeFile.FindFirstKey(nHash);
00362     while (iDir != HF_FIND_END)
00363     {
00364         HP_HEAPLENGTH nRecord;
00365         hfAttributeFile.Copy(iDir, &nRecord, &TempRecord);
00366 
00367         if (  TempRecord.attrKey.attrnum == nam->attrnum
00368            && TempRecord.attrKey.object  == nam->object)
00369         {
00370             hfAttributeFile.Remove(iDir);
00371         }
00372         iDir = hfAttributeFile.FindNextKey(iDir, nHash);
00373     }
00374 
00375     TempRecord.attrKey = *nam;
00376     memcpy(TempRecord.attrText, value, len);
00377     TempRecord.attrText[len-1] = '\0';
00378 
00379     // Insertion into DB.
00380     //
00381     if (!hfAttributeFile.Insert((HP_HEAPLENGTH)(len+sizeof(Aname)), nHash, &TempRecord))
00382     {
00383         Log.tinyprintf("cache_put((%d,%d), '%s', %u) failed" ENDLINE,
00384             nam->object, nam->attrnum, value, len);
00385     }
00386 
00387     if (!mudstate.bStandAlone)
00388     {
00389         // Update cache.
00390         //
00391         PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00392             &mudstate.acache_htab);
00393         if (pCacheEntry)
00394         {
00395             // It was in the cache, so delete it.
00396             //
00397             REMOVE_ENTRY(pCacheEntry);
00398             CacheSize -= pCacheEntry->nSize;
00399             hashdeleteLEN((char *)nam, sizeof(Aname), &mudstate.acache_htab);
00400             MEMFREE(pCacheEntry);
00401             pCacheEntry = NULL;
00402         }
00403 
00404         // Add information about the new entry back into the cache.
00405         //
00406         size_t nSizeOfEntry = sizeof(CENT_HDR) + len;
00407         pCacheEntry = (PCENT_HDR)MEMALLOC(nSizeOfEntry);
00408         if (pCacheEntry)
00409         {
00410             pCacheEntry->attrKey = *nam;
00411             pCacheEntry->nSize = nSizeOfEntry;
00412             CacheSize += pCacheEntry->nSize;
00413             memcpy((char *)(pCacheEntry+1), TempRecord.attrText, len);
00414             ADD_ENTRY(pCacheEntry);
00415             hashaddLEN(nam, sizeof(Aname), pCacheEntry,
00416                 &mudstate.acache_htab);
00417 
00418             TrimCache();
00419         }
00420     }
00421     return true;
00422 }
00423 
00424 bool cache_sync(void)
00425 {
00426     hfAttributeFile.Sync();
00427     return true;
00428 }
00429 
00430 // Delete this attribute from the database.
00431 //
00432 void cache_del(Aname *nam)
00433 {
00434     if (  !nam
00435        || !cache_initted)
00436     {
00437         return;
00438     }
00439 
00440 #ifndef WIN32
00441     if (mudstate.write_protect)
00442     {
00443         Log.tinyprintf("cache_del((%d,%d)) while database is write-protected" ENDLINE,
00444             nam->object, nam->attrnum);
00445         return;
00446     }
00447 #endif
00448 
00449     UINT32 nHash = CRC32_ProcessInteger2(nam->object, nam->attrnum);
00450 
00451     HP_DIRINDEX iDir = hfAttributeFile.FindFirstKey(nHash);
00452     while (iDir != HF_FIND_END)
00453     {
00454         HP_HEAPLENGTH nRecord;
00455         hfAttributeFile.Copy(iDir, &nRecord, &TempRecord);
00456 
00457         if (  TempRecord.attrKey.attrnum == nam->attrnum
00458            && TempRecord.attrKey.object == nam->object)
00459         {
00460             hfAttributeFile.Remove(iDir);
00461         }
00462         iDir = hfAttributeFile.FindNextKey(iDir, nHash);
00463     }
00464 
00465     if (!mudstate.bStandAlone)
00466     {
00467         // Update cache.
00468         //
00469         PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00470             &mudstate.acache_htab);
00471         if (pCacheEntry)
00472         {
00473             // It was in the cache, so delete it.
00474             //
00475             REMOVE_ENTRY(pCacheEntry);
00476             CacheSize -= pCacheEntry->nSize;;
00477             hashdeleteLEN((char *)nam, sizeof(Aname), &mudstate.acache_htab);
00478             MEMFREE(pCacheEntry);
00479             pCacheEntry = NULL;
00480         }
00481     }
00482 }

Generated on Mon May 28 04:40:07 2007 for MUX by  doxygen 1.4.7