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 #define DO_COMMIT
00015
00016 int cs_writes = 0;
00017 int cs_reads = 0;
00018 int cs_dels = 0;
00019 int cs_fails = 0;
00020 int cs_syncs = 0;
00021 int cs_dbreads = 0;
00022 int cs_dbwrites = 0;
00023 int cs_whits = 0;
00024 int cs_rhits = 0;
00025
00026 static const UINT32 CRC32_Table[256] =
00027 {
00028 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
00029 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
00030 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
00031 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
00032 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
00033 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
00034 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
00035 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
00036 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
00037 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
00038 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
00039 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
00040 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
00041 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
00042 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
00043 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
00044 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
00045 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
00046 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
00047 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
00048 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
00049 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
00050 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
00051 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
00052 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
00053 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
00054 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
00055 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
00056 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
00057 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
00058 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
00059 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
00060 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
00061 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
00062 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
00063 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
00064 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
00065 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
00066 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
00067 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
00068 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
00069 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
00070 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
00071 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
00072 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
00073 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
00074 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
00075 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
00076 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
00077 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
00078 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
00079 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
00080 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
00081 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
00082 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
00083 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
00084 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
00085 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
00086 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
00087 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
00088 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
00089 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
00090 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
00091 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
00092 };
00093
00094
00095
00096
00097 UINT32 CRC32_ProcessBuffer
00098 (
00099 UINT32 ulCrc,
00100 const void *arg_pBuffer,
00101 unsigned int nBuffer
00102 )
00103 {
00104 UINT8 *pBuffer = (UINT8 *)arg_pBuffer;
00105
00106 ulCrc = ~ulCrc;
00107 while (nBuffer--)
00108 {
00109 ulCrc = CRC32_Table[((UINT8)*pBuffer++) ^ (UINT8)ulCrc] ^ (ulCrc >> 8);
00110 }
00111 return ~ulCrc;
00112 }
00113
00114 UINT32 CRC32_ProcessInteger(UINT32 nInteger)
00115 {
00116 UINT32 ulCrc;
00117 ulCrc = ~nInteger;
00118 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00119 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00120 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00121 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00122 return ~ulCrc;
00123 }
00124
00125 UINT32 CRC32_ProcessInteger2(UINT32 nInteger1, UINT32 nInteger2)
00126 {
00127 UINT32 ulCrc;
00128 ulCrc = ~nInteger1;
00129 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00130 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00131 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00132 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00133 ulCrc ^= nInteger2;
00134 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00135 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00136 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00137 ulCrc = CRC32_Table[(UINT8)ulCrc] ^ (ulCrc >> 8);
00138 return ~ulCrc;
00139 }
00140
00141 #define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
00142 #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
00143 #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
00144 #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
00145 #define DO16(buf) DO8(buf,0); DO8(buf,8);
00146
00147 UINT32 HASH_ProcessBuffer
00148 (
00149 UINT32 ulHash,
00150 const void *arg_pBuffer,
00151 size_t nBuffer
00152 )
00153 {
00154 UINT8 *pBuffer = (UINT8 *)arg_pBuffer;
00155 ulHash = ~ulHash;
00156
00157 if (nBuffer <= 16)
00158 {
00159 pBuffer -= 16 - nBuffer;
00160 switch (nBuffer)
00161 {
00162 case 16: ulHash = CRC32_Table[pBuffer[0] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00163 case 15: ulHash = CRC32_Table[pBuffer[1] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00164 case 14: ulHash = CRC32_Table[pBuffer[2] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00165 case 13: ulHash = CRC32_Table[pBuffer[3] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00166 case 12: ulHash = CRC32_Table[pBuffer[4] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00167 case 11: ulHash = CRC32_Table[pBuffer[5] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00168 case 10: ulHash = CRC32_Table[pBuffer[6] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00169 case 9: ulHash = CRC32_Table[pBuffer[7] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00170 #if defined(UNALIGNED32) && defined(WORDS_LITTLEENDIAN)
00171 case 8: ulHash ^= *(UINT32 *)(pBuffer + 8);
00172 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00173 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00174 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00175 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00176 ulHash ^= *(UINT32 *)(pBuffer + 12);
00177 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00178 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00179 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00180 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00181 return ~ulHash;
00182 #else
00183 case 8: ulHash = CRC32_Table[pBuffer[8] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00184 #endif
00185
00186 case 7: ulHash = CRC32_Table[pBuffer[9] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00187 case 6: ulHash = CRC32_Table[pBuffer[10] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00188 case 5: ulHash = CRC32_Table[pBuffer[11] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00189 #if defined(UNALIGNED32) && defined(WORDS_LITTLEENDIAN)
00190 case 4: ulHash ^= *(UINT32 *)(pBuffer + 12);
00191 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00192 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00193 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00194 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00195 return ~ulHash;
00196 #else
00197 case 4: ulHash = CRC32_Table[pBuffer[12] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00198 #endif
00199
00200 case 3: ulHash = CRC32_Table[pBuffer[13] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00201 case 2: ulHash = CRC32_Table[pBuffer[14] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00202 case 1: ulHash = CRC32_Table[pBuffer[15] ^ (UINT8)ulHash] ^ (ulHash >> 8);
00203 case 0: return ~ulHash;
00204 }
00205 }
00206
00207 size_t nSmall = nBuffer & 15;
00208 size_t nMedium = (nBuffer >> 4) & 255;
00209 size_t nLarge = nBuffer >> 12;
00210
00211 UINT32 s1 = ulHash & 0xFFFF;
00212 UINT32 s2 = (ulHash >> 16) & 0xFFFF;
00213
00214 while (nLarge--)
00215 {
00216 int k = 256;
00217 while (k)
00218 {
00219 DO16(pBuffer);
00220 pBuffer += 16;
00221 k--;
00222 }
00223 ulHash = ~s1;
00224 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00225 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00226 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00227 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00228 ulHash ^= s2;
00229 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00230 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00231 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00232 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00233 ulHash = ~ulHash;
00234 s1 = ulHash & 0xFFFF;
00235 s2 = (ulHash >> 16) & 0xFFFF;
00236 }
00237
00238 while (nMedium--)
00239 {
00240 DO16(pBuffer);
00241 pBuffer += 16;
00242 }
00243
00244 pBuffer -= 15 - nSmall;
00245 switch (nSmall)
00246 {
00247 case 15: s1 += pBuffer[0]; s2 += s1;
00248 case 14: s1 += pBuffer[1]; s2 += s1;
00249 case 13: s1 += pBuffer[2]; s2 += s1;
00250 case 12: s1 += pBuffer[3]; s2 += s1;
00251 case 11: s1 += pBuffer[4]; s2 += s1;
00252 case 10: s1 += pBuffer[5]; s2 += s1;
00253 case 9: s1 += pBuffer[6]; s2 += s1;
00254 case 8: s1 += pBuffer[7]; s2 += s1;
00255 case 7: s1 += pBuffer[8]; s2 += s1;
00256 case 6: s1 += pBuffer[9]; s2 += s1;
00257 case 5: s1 += pBuffer[10]; s2 += s1;
00258 case 4: s1 += pBuffer[11]; s2 += s1;
00259 case 3: s1 += pBuffer[12]; s2 += s1;
00260 case 2: s1 += pBuffer[13]; s2 += s1;
00261 case 1: s1 += pBuffer[14]; s2 += s1;
00262 case 0: break;
00263 }
00264
00265 ulHash = ~s1;
00266 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00267 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00268 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00269 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00270 ulHash ^= s2;
00271 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00272 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00273 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00274 ulHash = CRC32_Table[(UINT8)ulHash] ^ (ulHash >> 8);
00275 return ~ulHash;
00276 }
00277
00278 #define NUMBER_OF_PRIMES 177
00279 const int Primes[NUMBER_OF_PRIMES] =
00280 {
00281
00282 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
00283 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151,
00284 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
00285 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337,
00286 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
00287 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
00288 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641,
00289 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
00290 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857,
00291 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971,
00292 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 0
00293 };
00294
00295 static void ChoosePrimes(int TableSize, HP_HEAPOFFSET HashPrimes[16])
00296 {
00297 int LargestPrime = TableSize/2;
00298 if (LargestPrime > Primes[NUMBER_OF_PRIMES-2])
00299 {
00300 LargestPrime = Primes[NUMBER_OF_PRIMES-2];
00301 }
00302 int Spacing = LargestPrime/16;
00303
00304
00305
00306
00307
00308 int iZone, iPrime;
00309 for (iZone = 1, iPrime = 0; iPrime < 16; iZone += Spacing)
00310 {
00311
00312
00313
00314 int Lower = Primes[0];
00315 for (int jPrime = 0; Primes[jPrime] != 0; jPrime++)
00316 {
00317 if (jPrime != 0 && TableSize % Primes[jPrime] == 0) continue;
00318 int Upper = Primes[jPrime];
00319 if (Lower <= iZone && iZone <= Upper)
00320 {
00321
00322
00323 if (iZone - Lower <= Upper - iZone)
00324 {
00325 HashPrimes[iPrime++] = Lower;
00326 }
00327 else
00328 {
00329 HashPrimes[iPrime++] = Upper;
00330 }
00331 break;
00332 }
00333 Lower = Upper;
00334 }
00335 }
00336
00337
00338
00339 for (iPrime = 0; iPrime < 16; iPrime += 2)
00340 {
00341 HashPrimes[iPrime] = TableSize-HashPrimes[iPrime];
00342 }
00343
00344
00345
00346
00347 for (iPrime = 0; iPrime < 16-1; iPrime++)
00348 {
00349 int Pick = (int)RandomINT32(0, 15-iPrime);
00350 HP_HEAPOFFSET Temp = HashPrimes[Pick];
00351 HashPrimes[Pick] = HashPrimes[15-iPrime];
00352 HashPrimes[15-iPrime] = Temp;
00353 }
00354 }
00355
00356 static const UINT32 anGroupMask[33] =
00357 {
00358 0x00000000U,
00359 0x80000000U, 0xC0000000U, 0xE0000000U, 0xF0000000U,
00360 0xF8000000U, 0xFC000000U, 0xFE000000U, 0xFF000000U,
00361 0xFF800000U, 0xFFC00000U, 0xFFE00000U, 0xFFF00000U,
00362 0xFFF80000U, 0xFFFC0000U, 0xFFFE0000U, 0xFFFF0000U,
00363 0xFFFF8000U, 0xFFFFC000U, 0xFFFFE000U, 0xFFFFF000U,
00364 0xFFFFF800U, 0xFFFFFC00U, 0xFFFFFE00U, 0xFFFFFF00U,
00365 0xFFFFFF80U, 0xFFFFFFC0U, 0xFFFFFFE0U, 0xFFFFFFF0U,
00366 0xFFFFFFF8U, 0xFFFFFFFCU, 0xFFFFFFFEU, 0xFFFFFFFFU
00367 };
00368
00369 bool CHashPage::Allocate(unsigned int nPageSize)
00370 {
00371 if (m_nPageSize) return false;
00372
00373 m_nPageSize = nPageSize;
00374 m_pPage = new unsigned char[nPageSize];
00375 if (m_pPage)
00376 {
00377 return true;
00378 }
00379 return false;
00380 }
00381
00382 CHashPage::CHashPage(void)
00383 {
00384 m_nPageSize = 0;
00385 m_pPage = 0;
00386 }
00387
00388 CHashPage::~CHashPage(void)
00389 {
00390 if (m_pPage)
00391 {
00392 delete [] m_pPage;
00393 m_pPage = 0;
00394 }
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 void CHashPage::GetStats
00407 (
00408 HP_HEAPLENGTH nExtra,
00409 int *pnRecords,
00410 HP_HEAPLENGTH *pnAllocatedSize,
00411 int *pnGoodDirSize
00412 )
00413 {
00414 unsigned nSize = 0;
00415 unsigned nCount = 0;
00416 unsigned nGoodDirSize = 100;
00417
00418
00419
00420 for (UINT32 iDir = 0; iDir < m_pHeader->m_nDirSize; iDir++)
00421 {
00422 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00423 {
00424 nCount++;
00425 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]);
00426 HP_HEAPLENGTH nRequired = EXPAND_TO_BOUNDARY(
00427 HP_SIZEOF_HEAPNODE + pNode->u.s.nRecordSize);
00428
00429 if (nRequired < HP_MIN_HEAP_ALLOC)
00430 {
00431 nRequired = HP_MIN_HEAP_ALLOC;
00432 }
00433 nSize += nRequired;
00434 }
00435 }
00436 *pnRecords = nCount;
00437 *pnAllocatedSize = nSize;
00438
00439
00440
00441
00442 if ( nExtra != 0
00443 || nCount != 0)
00444 {
00445 UINT32 nSpace = (UINT32)( ((unsigned char *)m_pTrailer)
00446 - ((unsigned char *)m_pDirectory));
00447 UINT32 nMinDirSize = nCount;
00448 UINT32 nMaxDirSize = (nSpace - nSize)/sizeof(HP_HEAPOFFSET);
00449
00450 if (nExtra)
00451 {
00452 nExtra += HP_SIZEOF_HEAPNODE;
00453 if (nExtra < HP_MIN_HEAP_ALLOC)
00454 {
00455 nExtra = HP_MIN_HEAP_ALLOC;
00456 }
00457 nExtra = EXPAND_TO_BOUNDARY(nExtra);
00458 nCount++;
00459 nSize += nExtra;
00460 }
00461
00462 #define FILL_FACTOR 1
00463 UINT32 nAverageSize = (nSize + nCount/2)/nCount;
00464 UINT32 nHeapGoal = (nSpace * nAverageSize)/(nAverageSize + sizeof(HP_HEAPOFFSET) + FILL_FACTOR);
00465 nGoodDirSize = (UINT32)((nSpace - nHeapGoal + sizeof(HP_HEAPOFFSET)/2)/sizeof(HP_HEAPOFFSET));
00466 if (nGoodDirSize < nMinDirSize)
00467 {
00468 nGoodDirSize = nMinDirSize;
00469 }
00470 else if (nGoodDirSize > nMaxDirSize)
00471 {
00472 nGoodDirSize = nMaxDirSize;
00473 }
00474 }
00475 *pnGoodDirSize = nGoodDirSize;
00476 }
00477
00478
00479 void CHashPage::SetFixedPointers(void)
00480 {
00481 m_pHeader = (HP_PHEADER)m_pPage;
00482 m_pDirectory = (HP_PHEAPOFFSET)(m_pHeader+1);
00483 m_pTrailer = (HP_PTRAILER)(m_pPage + m_nPageSize - sizeof(HP_TRAILER));
00484 }
00485
00486 void CHashPage::Empty(HP_DIRINDEX arg_nDepth, UINT32 arg_nHashGroup, HP_DIRINDEX arg_nDirSize)
00487 {
00488 memset(m_pPage, 0, m_nPageSize);
00489
00490 SetFixedPointers();
00491
00492 m_pHeader->m_nDepth = arg_nDepth;
00493 m_pHeader->m_nDirSize = arg_nDirSize;
00494 m_pHeader->m_nHashGroup = arg_nHashGroup;
00495 m_pHeader->m_nTotalInsert = 0;
00496 m_pHeader->m_nDirEmptyLeft = arg_nDirSize;
00497 if (arg_nDirSize > 0)
00498 {
00499 ChoosePrimes(arg_nDirSize, m_pHeader->m_Primes);
00500 for (UINT32 iDir = 0; iDir < arg_nDirSize; iDir++)
00501 {
00502 m_pDirectory[iDir] = HP_DIR_EMPTY;
00503 }
00504 }
00505 SetVariablePointers();
00506
00507
00508
00509 HP_PHEAPNODE pNode = (HP_PHEAPNODE)m_pHeapStart;
00510 pNode->nBlockSize = (HP_HEAPLENGTH)(m_pHeapEnd - m_pHeapStart);
00511 pNode->u.oNext = HP_NIL_OFFSET;
00512 m_pHeader->m_oFreeList = 0;
00513 }
00514
00515 #ifdef HP_PROTECTION
00516 void CHashPage::Protection(void)
00517 {
00518 UINT32 ul = HASH_ProcessBuffer(0, m_pPage, m_nPageSize-sizeof(HP_TRAILER));
00519 m_pTrailer->m_checksum = ul;
00520 }
00521
00522 bool CHashPage::Validate(void)
00523 {
00524 UINT32 ul = HASH_ProcessBuffer(0, m_pPage, m_nPageSize-sizeof(HP_TRAILER));
00525 if (ul != m_pTrailer->m_checksum)
00526 {
00527 return false;
00528 }
00529 return true;
00530 }
00531
00532
00533
00534
00535
00536
00537 bool CHashPage::ValidateAllocatedBlock(UINT32 iDir)
00538 {
00539 if (iDir >= m_pHeader->m_nDirSize) return false;
00540 if (m_pDirectory[iDir] >= HP_DIR_DELETED)
00541 return false;
00542
00543
00544
00545 unsigned char *pBlockStart = m_pHeapStart + m_pDirectory[iDir];
00546 unsigned char *pBlockEnd = pBlockStart + HP_MIN_HEAP_ALLOC;
00547 if (pBlockStart < m_pHeapStart || m_pHeapEnd <= pBlockEnd)
00548 {
00549
00550
00551
00552
00553
00554 m_pDirectory[iDir] = HP_DIR_DELETED;
00555 }
00556 else
00557 {
00558 HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart;
00559 pBlockEnd = pBlockStart + pNode->nBlockSize;
00560 if (m_pHeapEnd < pBlockEnd || pNode->u.s.nRecordSize > pNode->nBlockSize)
00561 {
00562
00563
00564
00565 m_pDirectory[iDir] = HP_DIR_DELETED;
00566 }
00567 else
00568 {
00569 return true;
00570 }
00571 }
00572 return false;
00573 }
00574
00575 bool CHashPage::ValidateFreeBlock(HP_HEAPOFFSET oBlock)
00576 {
00577
00578
00579 if (m_pHeader->m_oFreeList == HP_NIL_OFFSET)
00580 {
00581 return false;
00582 }
00583
00584
00585
00586 unsigned char *pBlockStart = m_pHeapStart + oBlock;
00587 unsigned char *pBlockEnd = pBlockStart + HP_MIN_HEAP_ALLOC;
00588 if (pBlockStart < m_pHeapStart || m_pHeapEnd < pBlockEnd)
00589 {
00590
00591
00592
00593
00594
00595 m_pHeader->m_oFreeList = HP_NIL_OFFSET;
00596 }
00597 else
00598 {
00599 HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart;
00600 pBlockEnd = pBlockStart + pNode->nBlockSize;
00601 if (m_pHeapEnd < pBlockEnd)
00602 {
00603
00604
00605 m_pHeader->m_oFreeList = HP_NIL_OFFSET;
00606 }
00607 else
00608 {
00609 return true;
00610 }
00611 }
00612 return false;
00613 }
00614
00615
00616
00617 bool CHashPage::ValidateFreeList(void)
00618 {
00619 HP_HEAPOFFSET oCurrent = m_pHeader->m_oFreeList;
00620 while (oCurrent != HP_NIL_OFFSET)
00621 {
00622 if (ValidateFreeBlock(oCurrent))
00623 {
00624 HP_PHEAPNODE pCurrent = (HP_PHEAPNODE)(m_pHeapStart + oCurrent);
00625 if (oCurrent >= pCurrent->u.oNext)
00626 {
00627 Log.WriteString("CHashPage::ValidateFreeList - Free list is corrupt." ENDLINE);
00628 m_pHeader->m_oFreeList = HP_NIL_OFFSET;
00629 return false;
00630 }
00631 oCurrent = pCurrent->u.oNext;
00632 }
00633 else
00634 {
00635 Log.WriteString("CHashPage::ValidateFreeList - Free list is corrupt." ENDLINE);
00636 m_pHeader->m_oFreeList = HP_NIL_OFFSET;
00637 return false;
00638 }
00639 }
00640 return true;
00641 }
00642 #endif // HP_PROTECTION
00643
00644
00645
00646 int CHashPage::Insert(HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord)
00647 {
00648 int ret = HP_INSERT_SUCCESS;
00649 m_pHeader->m_nTotalInsert++;
00650 for (int nTries = 0; nTries < 2; nTries++)
00651 {
00652 #ifdef HP_PROTECTION
00653
00654
00655 HP_DIRINDEX nDepth = m_pHeader->m_nDepth;
00656 if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup)
00657 {
00658 Log.WriteString("CHashPage::Insert - Inserting into the wrong page." ENDLINE);
00659 return HP_INSERT_ERROR_ILLEGAL;
00660 }
00661 #endif // HP_PROTECTION
00662
00663
00664
00665 int di = m_pHeader->m_Primes[nHash & 15];
00666 int iDir = (nHash >> 4) % (m_pHeader->m_nDirSize);
00667 m_nProbesLeft = m_pHeader->m_nDirSize;
00668 while (m_nProbesLeft-- && (m_pDirectory[iDir] < HP_DIR_DELETED))
00669 {
00670 iDir += di;
00671 if (iDir >= (m_pHeader->m_nDirSize))
00672 {
00673 iDir -= (m_pHeader->m_nDirSize);
00674 }
00675 }
00676 if (m_nProbesLeft >= 0)
00677 {
00678 if (m_pHeader->m_nDirEmptyLeft < m_nDirEmptyTrigger)
00679 {
00680 if (!Defrag(nRecord))
00681 {
00682 return HP_INSERT_ERROR_FULL;
00683 }
00684 ret = HP_INSERT_SUCCESS_DEFRAG;
00685 continue;
00686 }
00687 if (HeapAlloc(iDir, nRecord, nHash, pRecord))
00688 {
00689 return ret;
00690 }
00691 }
00692 if (!Defrag(nRecord))
00693 {
00694 return HP_INSERT_ERROR_FULL;
00695 }
00696 ret = HP_INSERT_SUCCESS_DEFRAG;
00697 }
00698 return HP_INSERT_ERROR_FULL;
00699 }
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709 HP_DIRINDEX CHashPage::FindFirstKey(UINT32 nHash, unsigned int *numchecks)
00710 {
00711 #ifdef HP_PROTECTION
00712
00713
00714 HP_DIRINDEX nDepth = m_pHeader->m_nDepth;
00715 if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup)
00716 return HP_DIR_EMPTY;
00717 #endif // HP_PROTECTION
00718
00719 const int nDirSize = m_pHeader->m_nDirSize;
00720
00721
00722
00723 int iDir = (nHash >> 4) % nDirSize;
00724 int sOffset = m_pDirectory[iDir];
00725 if ((unsigned int)sOffset < HP_DIR_DELETED)
00726 {
00727 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + sOffset);
00728 if (pNode->u.s.nHash == nHash)
00729 {
00730 m_nProbesLeft = nDirSize - 1;
00731 *numchecks = 1;
00732 return iDir;
00733 }
00734 }
00735 else if (HP_DIR_EMPTY == sOffset)
00736 {
00737 m_nProbesLeft = nDirSize;
00738 *numchecks = 0;
00739 return HP_DIR_EMPTY;
00740 }
00741
00742
00743
00744
00745 m_nProbesLeft = nDirSize - 1;
00746 int di = m_pHeader->m_Primes[nHash & 15];
00747
00748 iDir += di;
00749 if (iDir >= nDirSize)
00750 {
00751 iDir -= nDirSize;
00752 }
00753 sOffset = m_pDirectory[iDir];
00754
00755 while (sOffset != HP_DIR_EMPTY)
00756 {
00757 m_nProbesLeft--;
00758 if (sOffset != HP_DIR_DELETED)
00759 {
00760 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + sOffset);
00761 if (pNode->u.s.nHash == nHash)
00762 {
00763 *numchecks = nDirSize - m_nProbesLeft;
00764 return iDir;
00765 }
00766 }
00767
00768 if (!m_nProbesLeft) break;
00769
00770 iDir += di;
00771 if (iDir >= nDirSize)
00772 {
00773 iDir -= nDirSize;
00774 }
00775 sOffset = m_pDirectory[iDir];
00776 }
00777 *numchecks = nDirSize - m_nProbesLeft;
00778 return HP_DIR_EMPTY;
00779 }
00780
00781
00782
00783
00784
00785 HP_DIRINDEX CHashPage::FindNextKey(HP_DIRINDEX iDir, UINT32 nHash, unsigned int *numchecks)
00786 {
00787 *numchecks = 0;
00788
00789 #ifdef HP_PROTECTION
00790
00791
00792 HP_DIRINDEX nDepth = m_pHeader->m_nDepth;
00793 if ((nHash & anGroupMask[nDepth]) != m_pHeader->m_nHashGroup)
00794 return HP_DIR_EMPTY;
00795 #endif // HP_PROTECTION
00796
00797 int nDirSize = m_pHeader->m_nDirSize;
00798
00799
00800
00801
00802 int di = m_pHeader->m_Primes[nHash & 15];
00803 iDir += di;
00804 if (iDir >= nDirSize)
00805 {
00806 iDir -= nDirSize;
00807 }
00808 while (m_nProbesLeft && (m_pDirectory[iDir] != HP_DIR_EMPTY))
00809 {
00810 m_nProbesLeft--;
00811 (*numchecks)++;
00812 if (m_pDirectory[iDir] != HP_DIR_DELETED)
00813 {
00814 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00815 {
00816 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]);
00817 if (pNode->u.s.nHash == nHash) return iDir;
00818 }
00819 }
00820 iDir += di;
00821 if (iDir >= nDirSize)
00822 {
00823 iDir -= nDirSize;
00824 }
00825 }
00826 return HP_DIR_EMPTY;
00827 }
00828
00829
00830
00831
00832 bool CHashPage::HeapAlloc(HP_DIRINDEX iDir, HP_HEAPLENGTH nRecord, UINT32 nHash, void *pRecord)
00833 {
00834
00835 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00836 {
00837 return false;
00838 }
00839
00840
00841
00842 HP_HEAPLENGTH nRequired = EXPAND_TO_BOUNDARY(HP_SIZEOF_HEAPNODE + nRecord);
00843 if (nRequired < HP_MIN_HEAP_ALLOC)
00844 {
00845 nRequired = HP_MIN_HEAP_ALLOC;
00846 }
00847
00848
00849
00850 HP_HEAPOFFSET oNext = m_pHeader->m_oFreeList;
00851 HP_PHEAPOFFSET poPrev = &(m_pHeader->m_oFreeList);
00852 while (oNext != HP_NIL_OFFSET)
00853 {
00854 #if 0
00855 if (!ValidateFreeBlock(oPrevious))
00856 {
00857 ValidateFreeList();
00858 return false;
00859 }
00860 #endif // 0
00861 unsigned char *pBlockStart = m_pHeapStart + oNext;
00862 HP_PHEAPNODE pNode = (HP_PHEAPNODE)pBlockStart;
00863 if (pNode->nBlockSize >= nRequired)
00864 {
00865
00866
00867
00868
00869 HP_HEAPLENGTH nNewBlockSize = pNode->nBlockSize - nRequired;
00870 if (nNewBlockSize >= EXPAND_TO_BOUNDARY(HP_MIN_HEAP_ALLOC+1))
00871 {
00872
00873
00874 HP_PHEAPNODE pNewNode = (HP_PHEAPNODE)(pBlockStart + nRequired);
00875 pNewNode->nBlockSize = nNewBlockSize;
00876 pNewNode->u.oNext = pNode->u.oNext;
00877
00878
00879
00880 pNode->nBlockSize = nRequired;
00881 pNode->u.s.nHash = nHash;
00882 pNode->u.s.nRecordSize = nRecord;
00883
00884
00885
00886 *poPrev += nRequired;
00887 }
00888 else
00889 {
00890
00891
00892 *poPrev = pNode->u.oNext;
00893 pNode->u.s.nHash = nHash;
00894 pNode->u.s.nRecordSize = nRecord;
00895 }
00896 memcpy(pNode+1, pRecord, nRecord);
00897 if (m_pDirectory[iDir] == HP_DIR_EMPTY)
00898 {
00899 m_pHeader->m_nDirEmptyLeft--;
00900 }
00901 m_pDirectory[iDir] = (HP_HEAPOFFSET)(pBlockStart - m_pHeapStart);
00902 return true;
00903 }
00904 poPrev = &(pNode->u.oNext);
00905 oNext = pNode->u.oNext;
00906 }
00907 return false;
00908 }
00909
00910
00911
00912
00913 void CHashPage::HeapFree(HP_DIRINDEX iDir)
00914 {
00915
00916 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00917 {
00918 HP_HEAPOFFSET oBlock = m_pDirectory[iDir];
00919 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + oBlock);
00920
00921
00922
00923
00924
00925 HP_HEAPLENGTH nBlockSize = pNode->nBlockSize;
00926 memset(pNode, 0, nBlockSize);
00927 pNode->nBlockSize = nBlockSize;
00928
00929
00930
00931 pNode->u.oNext = m_pHeader->m_oFreeList;
00932 m_pHeader->m_oFreeList = oBlock;
00933 m_pDirectory[iDir] = HP_DIR_DELETED;
00934 }
00935 }
00936
00937 void CHashPage::HeapCopy(HP_DIRINDEX iDir, HP_PHEAPLENGTH pnRecord, void *pRecord)
00938 {
00939 if (pnRecord == 0 || pRecord == 0) return;
00940
00941 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00942 {
00943 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]);
00944
00945
00946
00947 *pnRecord = pNode->u.s.nRecordSize;
00948 memcpy(pRecord, pNode+1, pNode->u.s.nRecordSize);
00949 }
00950 }
00951
00952 void CHashPage::HeapUpdate(HP_DIRINDEX iDir, HP_HEAPLENGTH nRecord, void *pRecord)
00953 {
00954 if (nRecord == 0 || pRecord == 0) return;
00955
00956 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00957 {
00958 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]);
00959
00960 if (pNode->u.s.nRecordSize != nRecord) return;
00961 memcpy(pNode+1, pRecord, nRecord);
00962 }
00963 }
00964
00965 bool CHashPage::Split(CHashPage &hp0, CHashPage &hp1)
00966 {
00967
00968
00969 int nRecords;
00970 HP_HEAPLENGTH nAllocatedSize;
00971 int nGoodDirSize;
00972 GetStats(0, &nRecords, &nAllocatedSize, &nGoodDirSize);
00973 if (nRecords == 0)
00974 {
00975 Log.WriteString("Why are we splitting a page with no records in it?" ENDLINE);
00976 return false;
00977 }
00978
00979
00980
00981 int nNewDepth = m_pHeader->m_nDepth + 1;
00982 UINT32 nBitMask = 1 << (32-nNewDepth);
00983 UINT32 nHashGroup0 = m_pHeader->m_nHashGroup & (~nBitMask);
00984 UINT32 nHashGroup1 = nHashGroup0 | nBitMask;
00985 hp0.Empty(nNewDepth, nHashGroup0, nGoodDirSize);
00986 hp1.Empty(nNewDepth, nHashGroup1, nGoodDirSize);
00987 for (int iDir = 0; iDir < m_pHeader->m_nDirSize; iDir++)
00988 {
00989 if (m_pDirectory[iDir] < HP_DIR_DELETED)
00990 {
00991 HP_PHEAPNODE pNode = (HP_PHEAPNODE)(m_pHeapStart + m_pDirectory[iDir]);
00992 UINT32 nHash = pNode->u.s.nHash;
00993 if ((nHash & anGroupMask[nNewDepth]) == (nHashGroup0 & anGroupMask[nNewDepth]))
00994 {
00995 if (!IS_HP_SUCCESS(hp0.Insert(pNode->u.s.nRecordSize, nHash, pNode+1)))
00996 {
00997 Log.WriteString("CHashPage::Split - Ran out of room." ENDLINE);
00998 return false;
00999 }
01000 }
01001 else if ((nHash & anGroupMask[nNewDepth]) == (nHashGroup1 & anGroupMask[nNewDepth]))
01002 {
01003 if (!IS_HP_SUCCESS(hp1.Insert(pNode->u.s.nRecordSize, nHash, pNode+1)))
01004 {
01005 Log.WriteString("CHashPage::Split - Ran out of room." ENDLINE);
01006 return false;
01007 }
01008 }
01009 else
01010 {
01011 Log.WriteString("CHashPage::Split - This record fits in neither page...lost." ENDLINE);
01012 return false;
01013 }
01014 }
01015 }
01016 #if 0
01017 int nRecords0, nRecords1;
01018 HP_HEAPLENGTH nAllocatedSize0, nAllocatedSize1;
01019 int temp;
01020 hp0.GetStats(0, &nRecords0, &nAllocatedSize0, &temp);
01021 hp1.GetStats(0, &nRecords1, &nAllocatedSize1, &temp);
01022 Log.tinyprintf("Split (%d %d) page into (%d %d) and (%d %d)" ENDLINE,
01023 nRecords, nAllocatedSize, nRecords0, nAllocatedSize0, nRecords1,
01024 nAllocatedSize1);
01025 if (nRecords0 + nRecords1 != nRecords)
01026 {
01027 Log.WriteString("Lost something" ENDLINE);
01028 return false;
01029 }
01030 #endif // 0
01031 return true;
01032 }
01033
01034 void CHashPage::GetRange
01035 (
01036 UINT32 arg_nDirDepth,
01037 UINT32 &nStart,
01038 UINT32 &nEnd
01039 )
01040 {
01041 UINT32 nBase = 0;
01042 int nShift = 32 - arg_nDirDepth;
01043 if (arg_nDirDepth > 0)
01044 {
01045 nBase = m_pHeader->m_nHashGroup >> nShift;
01046 }
01047 UINT32 ulMask = anGroupMask[nShift + m_pHeader->m_nDepth];
01048 nStart = nBase & ulMask;
01049 nEnd = nBase | ~ulMask;
01050 }
01051
01052 #ifdef WIN32
01053 bool CHashPage::WritePage(HANDLE hFile, HF_FILEOFFSET oWhere)
01054 {
01055 cs_dbwrites++;
01056 for ( ; ; MuxAlarm.Sleep(time_250ms))
01057 {
01058 if (SetFilePointer(hFile, oWhere, 0, FILE_BEGIN) == 0xFFFFFFFFUL)
01059 {
01060 Log.tinyprintf("CHashPage::Write - SetFilePointer error %u." ENDLINE, GetLastError());
01061 continue;
01062 }
01063 DWORD nWritten;
01064 if (!WriteFile(hFile, m_pPage, m_nPageSize, &nWritten, 0) || nWritten != m_nPageSize)
01065 {
01066