00001
00002
00003
00004
00005
00006
00007
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
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
00129
00130 if (pEntry == pCacheHead)
00131 {
00132 if (pEntry == pCacheTail)
00133 {
00134
00135
00136
00137
00138
00139
00140 pCacheHead = pCacheTail = 0;
00141 }
00142 else
00143 {
00144
00145
00146
00147
00148
00149
00150 pCacheHead = pEntry->pNextEntry;
00151 pCacheHead->pPrevEntry = 0;
00152 pEntry->pNextEntry = 0;
00153 }
00154 }
00155 else if (pEntry == pCacheTail)
00156 {
00157
00158
00159
00160
00161
00162
00163 pCacheTail = pEntry->pPrevEntry;
00164 pCacheTail->pNextEntry = 0;
00165 pEntry->pPrevEntry = 0;
00166 }
00167 else
00168 {
00169
00170
00171
00172
00173
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
00200
00201 while (CacheSize > mudconf.max_cache_size)
00202 {
00203
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
00234
00235 pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00236 &mudstate.acache_htab);
00237 if (pCacheEntry)
00238 {
00239
00240
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
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
00295
00296 if (!mudstate.bStandAlone)
00297 {
00298
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
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
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
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
00390
00391 PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00392 &mudstate.acache_htab);
00393 if (pCacheEntry)
00394 {
00395
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
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
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
00468
00469 PCENT_HDR pCacheEntry = (PCENT_HDR)hashfindLEN(nam, sizeof(Aname),
00470 &mudstate.acache_htab);
00471 if (pCacheEntry)
00472 {
00473
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 }