- Timestamp:
- Apr 14, 2009 7:21:15 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/kdepdb.c
r2337 r2339 48 48 #endif 49 49 50 #ifdef WINDOWS32 51 # include <io.h> 52 # include <process.h> 50 #if K_OS == K_WINDOWS 53 51 # include <Windows.h> 54 # define PARSE_IN_WORKER 55 #endif 52 #else 53 # include <unistd.h> 54 # include <sys/mman.h> 55 #endif 56 56 57 57 58 /******************************************************************************* … … 353 354 /** The string table file. */ 354 355 KDEPDBSTRTAB *pStrTab; 356 /** The handle of the string table file. */ 357 KDEPDBFH hStrTab; 355 358 /** The end of the allocated string table indexes (i.e. when to grow the 356 359 * file). */ 357 360 KU32 iStringAlloced; 358 /** The handle of the string table file. */359 KDEPDBFH hStrTab;360 361 } KDEPDBINTSTRTAB; 361 362 … … 412 413 static void *kDepDbAlloc(KSIZE cb); 413 414 static void kDepDbFree(void *pv); 414 static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename); 415 static void kDepDbFHInit(KDEPDBFH *pFH); 416 static int kDepDbFHUpdateSize(KDEPDBFH *pFH); 417 static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfNew); 415 418 static int kDepDbFHClose(KDEPDBFH *pFH); 416 419 static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf); … … 427 430 } 428 431 429 430 432 /** free wrapper. */ 431 433 static void kDepDbFree(void *pv) … … 435 437 } 436 438 439 440 /** 441 * Initializes the file handle structure so closing it without first opening it 442 * will work smoothly. 443 * 444 * @param pFH The file handle structure. 445 */ 446 static void kDepDbFHInit(KDEPDBFH *pFH) 447 { 448 #if K_OS == K_OS_WINDOWS 449 pFH->hFile = INVALID_HANDLE_VALUE; 450 pFH->hMapObj = INVALID_HANDLE_VALUE; 451 #else 452 pFH->fd = -1; 453 #endif 454 pFH->cb = 0; 455 } 456 457 /** 458 * Updates the file size. 459 * 460 * @returns 0 on success. Some non-zero native error code on failure. 461 * @param pFH The file handle structure. 462 */ 463 static int kDepDbFHUpdateSize(KDEPDBFH *pFH) 464 { 465 #if K_OS == K_OS_WINDOWS 466 DWORD rc; 467 DWORD dwHigh; 468 DWORD dwLow; 469 470 SetLastError(0); 471 dwLow = GetFileSize(File, &High); 472 rc = GetLastError(); 473 if (rc) 474 { 475 pFH->cb = 0; 476 return (int)rc; 477 } 478 if (High) 479 pFH->cb = KU32_MAX; 480 else 481 pFH->cb = dwLow; 482 #else 483 off_t cb; 484 485 cb = lseek(pFH->fd, 0, SEEK_END); 486 if (cb == -1) 487 { 488 pFH->cb = 0; 489 return errno; 490 } 491 pFH->cb = cb; 492 if ((off_t)pFH->cb != cb) 493 pFH->cb = KU32_MAX; 494 #endif 495 return 0; 496 } 497 498 /** 499 * Opens an existing file or creates a new one. 500 * 501 * @returns 0 on success. Some non-zero native error code on failure. 502 * 503 * @param pFH The file handle structure. 504 * @param pszFilename The name of the file. 505 * @param fCreate Whether we should create the file or not. 506 * @param pfCreated Where to return whether we created it or not. 507 */ 508 static int kDepDbFHOpen(KDEPDBFH *pFH, const char *pszFilename, KBOOL fCreate, KBOOL *pfCreated) 509 { 510 int rc; 511 #if K_OS == K_OS_WINDOWS 512 SECURITY_ATTRIBUTES SecAttr; 513 514 SecAttr.bInheritHandle = FALSE; 515 SecAttr.lpSecurityDescriptor = NULL; 516 SecAttr.nLength = 0; 517 pFH->cb = 0; 518 SetLastError(0); 519 pFH->hFile = CreateFile(pszFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, &SecAttr, 520 fCreate ? OPEN_ALWAYS : OPEN_EXISTING, 0, NULL); 521 if (pFH->hFile == INVALID_HANDLE_VALUE) 522 return GetLastError(); 523 *pfCreated = GetLastError() == 0; 524 525 #else 526 int fFlags = O_RDWR; 527 # ifdef O_BINARY 528 fFlags |= O_BINARY; 529 # endif 530 pFH->cb = 0; 531 pFH->fd = open(pszFilename, fFlags, 0); 532 if (pFH->fd >= 0) 533 *pfCreated = K_FALSE; 534 else if (!fCreate) 535 return errno; 536 else 537 { 538 pFH->fd = open(pszFilename, fFlags | O_EXCL | O_CREATE, 0666); 539 if (pFH->fd < 0) 540 return errno; 541 *pfCreated = K_TRUE; 542 } 543 fcntl(pFH->fd, F_SETFD, FD_CLOEXEC); 544 #endif 545 546 /* update the size */ 547 rc = kDepDbFHUpdateSize(pFH); 548 if (rc) 549 kDepDbFHClose(pFH); 550 return rc; 551 } 552 553 /** 554 * Closes an open file. 555 * 556 * @returns 0 on success. Some non-zero native error code on failure. 557 * 558 * @param pFH The file handle structure. 559 */ 560 static int kDepDbFHClose(KDEPDBFH *pFH) 561 { 562 #if K_OS == K_OS_WINDOWS 563 if (pFH->hFile != INVALID_HANDLE_VALUE) 564 { 565 if (!CloseHandle(pFH->hFile)) 566 return GetLastError(); 567 pFH->hFile = INVALID_HANDLE_VALUE; 568 } 569 570 #else 571 if (pFH->fd >= 0) 572 { 573 if (close(pFH->fd) != 0) 574 return errno; 575 pFH->fd = -1; 576 } 577 #endif 578 pFH->cb = 0; 579 return 0; 580 } 581 582 /** 583 * Writes to a file. 584 * 585 * @returns 0 on success. Some non-zero native error code on failure. 586 * 587 * @param pFH The file handle structure. 588 * @param off The offset into the file to start writing at. 589 * @param pvBuf What to write. 590 * @param cbBuf How much to write. 591 */ 592 static int kDepDbFHWriteAt(KDEPDBFH *pFH, KU32 off, void const *pvBuf, KSIZE cbBuf) 593 { 594 #if K_OS == K_OS_WINDOWS 595 ULONG cbWritten; 596 597 if (SetFilePointer(pFH->hFile, off, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) 598 return GetLastError(); 599 600 if (!WriteFile(pFH->hFile, pvBuf, cbBuf, &cbWritten, NULL)) 601 return GetLastError(); 602 if (cbWritten != cbBuf) 603 return -1; 604 605 #else 606 ssize_t cbWritten; 607 if (lseek(pFH->fd, off, SEEK_SET) == -1) 608 return errno; 609 errno = 0; 610 cbWritten = write(pFH->fd, pvBuf, cbBuf); 611 if ((size_t)cbWritten != cbBuf) 612 return errno ? errno : EIO; 613 #endif 614 return kDepDbFHUpdateSize(pFH); 615 } 616 617 618 /** 619 * Creates a memory mapping of the file. 620 * 621 * @returns 0 on success. Some non-zero native error code on failure. 622 * 623 * @param pFH The file handle structure. 624 * @param ppvMap Where to return the map address. 625 */ 626 static int kDepDbFHMap(KDEPDBFH *pFH, void **ppvMap) 627 { 628 #if K_OS == K_OS_WINDOWS 629 *ppvMap = NULL; 630 return -1; 631 #else 632 *ppvMap = mmap(NULL, pFH->cb, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pFH->fd, 0); 633 if (*ppvMap == (void *)-1) 634 { 635 *ppvMap = NULL; 636 return errno; 637 } 638 #endif 639 return 0; 640 } 641 642 643 /** 644 * Flushes and destroys a memory of the file. 645 * 646 * @returns 0 on success. Some non-zero native error code on failure. 647 * 648 * @param pFH The file handle structure. 649 * @param ppvMap The pointer to the mapping pointer. This will be set to 650 * NULL on success. 651 */ 652 static int kDepDbFHUnmap(KDEPDBFH *pFH, void **ppvMap) 653 { 654 #if K_OS == K_OS_WINDOWS 655 return -1; 656 #else 657 if (msync(*ppvMap, pFH->cb, MS_SYNC) == -1) 658 return errno; 659 if (munmap(*ppvMap, pFH->cb) == -1) 660 return errno; 661 *ppvMap = NULL; 662 #endif 663 return 0; 664 } 665 666 667 /** 668 * Grows the memory mapping of the file. 669 * 670 * The content of the new space is undefined. 671 * 672 * @returns 0 on success. Some non-zero native error code on failure. 673 * 674 * @param pFH The file handle structure. 675 * @param cbNew The new mapping size. 676 * @param ppvMap The pointer to the mapping pointer. This may change and 677 * may be set to NULL on failure. 678 */ 679 static int kDepDbFHGrow(KDEPDBFH *pFH, KSIZE cbNew, void **ppvMap) 680 { 681 #if K_OS == K_OS_WINDOWS 682 return -1; 683 #else 684 if ((KU32)cbNew != cbNew) 685 return ERANGE; 686 if (cbNew <= pFH->cb) 687 return 0; 688 689 if (munmap(*ppvMap, pFH->cb) == -1) 690 return errno; 691 *ppvMap = NULL; 692 693 pFH->cb = cbNew; 694 return kDepDbFHMap(pFH, ppvMap); 695 #endif 696 } 697 698 699 /** Macro for reading an potentially unaligned 16-bit word from a string. */ 700 # if K_ARCH == K_ARCH_AMD64 \ 701 || K_ARCH == K_ARCH_X86_32 \ 702 || K_ARCH == K_ARCH_X86_16 703 # define kDepDbHashString_get_unaligned_16bits(ptr) ( *((const KU16 *)(ptr)) ) 704 # elif K_ENDIAN == K_ENDIAN_LITTLE 705 # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0]) \ 706 | (((const KU8 *)(ptr))[1] << 8) ) 707 # else 708 # define kDepDbHashString_get_unaligned_16bits(ptr) ( (((const KU8 *)(ptr))[0] << 8) \ 709 | (((const KU8 *)(ptr))[1]) ) 710 # endif 711 712 713 /** 714 * Hash a string. 715 * 716 * @returns Hash value. 717 * 718 * @param pszString The string to hash. 719 * @param cchString How much to hash. 720 */ 721 static KU32 kDepDbHashString(const char *pszString, size_t cchString) 722 { 723 /* 724 * Paul Hsieh hash SuperFast function: 725 * http://www.azillionmonkeys.com/qed/hash.html 726 */ 727 /** @todo A path for well aligned data should be added to speed up execution on 728 * alignment sensitive systems. */ 729 unsigned int uRem; 730 KU32 uHash; 731 KU32 uTmp; 732 733 assert(sizeof(KU8) == sizeof(char)); 734 735 /* main loop, walking on 2 x KU16 */ 736 uHash = cchString; 737 uRem = cchString & 3; 738 cchString >>= 2; 739 while (cchString > 0) 740 { 741 uHash += kDepDbHashString_get_unaligned_16bits(pszString); 742 uTmp = (kDepDbHashString_get_unaligned_16bits(pszString + 2) << 11) ^ uHash; 743 uHash = (uHash << 16) ^ uTmp; 744 pszString += 2 * sizeof(KU16); 745 uHash += uHash >> 11; 746 cchString--; 747 } 748 749 /* the remainder */ 750 switch (uRem) 751 { 752 case 3: 753 uHash += kDepDbHashString_get_unaligned_16bits(pszString); 754 uHash ^= uHash << 16; 755 uHash ^= pszString[sizeof(KU16)] << 18; 756 uHash += uHash >> 11; 757 break; 758 case 2: 759 uHash += kDepDbHashString_get_unaligned_16bits(pszString); 760 uHash ^= uHash << 11; 761 uHash += uHash >> 17; 762 break; 763 case 1: 764 uHash += *pszString; 765 uHash ^= uHash << 10; 766 uHash += uHash >> 1; 767 break; 768 } 769 770 /* force "avalanching" of final 127 bits. */ 771 uHash ^= uHash << 3; 772 uHash += uHash >> 5; 773 uHash ^= uHash << 4; 774 uHash += uHash >> 17; 775 uHash ^= uHash << 25; 776 uHash += uHash >> 6; 777 778 return uHash; 779 } 437 780 438 781 … … 454 797 KDEPDBHASH const *pHash = pStrTab->pHash; 455 798 KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; 456 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;799 KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); 457 800 KU32 iHash; 458 801 … … 467 810 for (;;) 468 811 { 469 KU32 iString = pHash->auEntries[iHash];812 KU32 iString = K_LE2H_U32(pHash->auEntries[iHash]); 470 813 if (iString < iStringEnd) 471 814 { 472 815 KDEPDBSTRING const *pString = &paStrings[iString]; 473 if ( pString->uHash== uHash474 && pString->cchString== cchString816 if ( K_LE2H_U32(pString->uHash) == uHash 817 && K_LE2H_U32(pString->cchString) == cchString 475 818 && !memcmp(pString->szString, pszString, cchString)) 476 819 return iString; … … 492 835 * @returns 0 on success, -1 on failure. 493 836 * @param pStrTab The string table. 837 * @todo Rebuild from string table, we'll be accessing it anyways. 494 838 */ 495 839 static int kDepDbStrTabReHash(KDEPDBINTSTRTAB *pStrTab) 496 840 { 497 841 KDEPDBSTRING const *paStrings = &pStrTab->pStrTab->aStrings[0]; 498 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;842 KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); 499 843 KDEPDBHASH *pHash = pStrTab->pHash; 500 844 KDEPDBHASH HashHdr = *pHash; … … 525 869 * Popuplate the new table. 526 870 */ 527 HashHdr.cEntries = cEntriesNew;871 HashHdr.cEntries = K_LE2H_U32(cEntriesNew); 528 872 HashHdr.cCollisions = 0; 529 873 HashHdr.cUsedEntries = 0; … … 531 875 while (i-- > 0) 532 876 { 533 KU32 iString = pHash->auEntries[i];877 KU32 iString = K_LE2H_U32(pHash->auEntries[i]); 534 878 if (iString < iStringEnd) 535 879 { 536 880 KU32 iHash = (paStrings[iString].uHash % cEntriesNew); 537 if (pauNew[iHash] != K DEPDBHASH_UNUSED)881 if (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)) 538 882 { 539 883 do … … 541 885 iHash = (iHash + 1) % cEntriesNew; 542 886 HashHdr.cCollisions++; 543 } while (pauNew[iHash] != K DEPDBHASH_UNUSED);887 } while (pauNew[iHash] != K_H2LE_U32(KDEPDBHASH_UNUSED)); 544 888 } 545 889 pauNew[iHash] = iString; 546 HashHdr.c Entries++;890 HashHdr.cUsedEntries++; 547 891 } 548 892 else if ( iString != KDEPDBHASH_UNUSED 549 893 && iString != KDEPDBHASH_DELETED) 550 894 { 551 /* ignore any invalid entires for now */; 895 kDepDbFree(pauNew); 896 return -1; 552 897 } 553 898 } 899 HashHdr.cCollisions = K_H2LE_U32(HashHdr.cCollisions); 900 HashHdr.cUsedEntries = K_H2LE_U32(HashHdr.cUsedEntries); 554 901 555 902 /* … … 593 940 KDEPDBHASH *pHash = pStrTab->pHash; 594 941 KDEPDBSTRING *paStrings = &pStrTab->pStrTab->aStrings[0]; 595 KU32 const iStringEnd = pStrTab->pStrTab->iStringEnd;942 KU32 const iStringEnd = K_LE2H_U32(pStrTab->pStrTab->iStringEnd); 596 943 KU32 iInsertAt = KDEPDBHASH_UNUSED; 597 944 KU32 cCollisions = 0; … … 606 953 607 954 /* 608 * Hash lookup of the string. 955 * Hash lookup of the string, finding either an existing copy or where to 956 * insert the new string at in the hash table. 609 957 */ 610 958 iHash = uHash % pHash->cEntries; 611 959 for (;;) 612 960 { 613 iString = pHash->auEntries[iHash];961 iString = K_LE2H_U32(pHash->auEntries[iHash]); 614 962 if (iString < iStringEnd) 615 963 { 616 964 KDEPDBSTRING const *pString = &paStrings[iString]; 617 if ( pString->uHash== uHash618 && pString->cchString== cchString965 if ( K_LE2H_U32(pString->uHash) == uHash 966 && K_LE2H_U32(pString->cchString) == cchString 619 967 && !memcmp(pString->szString, pszString, cchString)) 620 968 return iString; … … 644 992 if (iStringEnd + cEntries > pStrTab->iStringAlloced) 645 993 { 646 KSIZE cbNewSize = K_ALIGN_Z((iStringEnd + cEntries) * sizeof(KDEPDBSTRING) + 64*1024, 256*1024); 994 KSIZE cbNewSize = K_ALIGN_Z((iStringEnd + cEntries) * sizeof(KDEPDBSTRING) + 64*1024, 256*1024); 995 KU32 iStringAlloced = (pStrTab->hStrTab.cb - K_OFFSETOF(KDEPDBSTRTAB, aStrings)) / sizeof(KDEPDBSTRING); 996 if ( iStringAlloced <= pStrTab->iStringAlloced 997 || iStringAlloced >= KDEPDBG_STRTAB_IDX_END 998 || iStringAlloced >= KDEPDBHASH_END) 999 return KDEPDBG_STRTAB_IDX_ERROR; 647 1000 if (kDepDbFHGrow(&pStrTab->hStrTab, cbNewSize, (void **)&pStrTab->pStrTab) != 0) 648 1001 return KDEPDBG_STRTAB_IDX_ERROR; 649 650 pStrTab->iStringAlloced = (cbNewSize - K_OFFSETOF(KDEPDBSTRTAB, aStrings)) / sizeof(KDEPDBSTRING); 1002 pStrTab->iStringAlloced = iStringAlloced; 651 1003 paStrings = &pStrTab->pStrTab->aStrings[0]; 652 1004 } 1005 653 1006 pNewString = &paStrings[iStringEnd]; 654 pNewString->uHash = uHash;655 pNewString->cchString = cchString;1007 pNewString->uHash = K_H2LE_U32(uHash); 1008 pNewString->cchString = K_H2LE_U32(cchString); 656 1009 memcpy(&pNewString->szString, pszString, cchString); 657 1010 pNewString->szString[cchString] = '\0'; 658 1011 659 pStrTab->pStrTab->iStringEnd = iStringEnd + cEntries;1012 pStrTab->pStrTab->iStringEnd = K_H2LE_U32(iStringEnd + cEntries); 660 1013 661 1014 /* 662 1015 * Insert hash table entry, rehash it if necessary. 663 1016 */ 664 pHash->auEntries[iInsertAt] = iStringEnd;665 pHash->cUsedEntries ++;666 pHash->cCollisions += cCollisions;667 if ( pHash->cUsedEntries > pHash->cEntries/ 3 * 21017 pHash->auEntries[iInsertAt] = K_H2LE_U32(iStringEnd); 1018 pHash->cUsedEntries = K_H2LE_U32(K_LE2H_U32(pHash->cUsedEntries) + 1); 1019 pHash->cCollisions = K_H2LE_U32(K_LE2H_U32(pHash->cCollisions) + cCollisions); 1020 if ( K_LE2H_U32(pHash->cUsedEntries) > K_LE2H_U32(pHash->cEntries) / 3 * 2 668 1021 && kDepDbStrTabReHash(pStrTab) != 0) 669 1022 return KDEPDBG_STRTAB_IDX_ERROR; … … 701 1054 702 1055 703 1056 /** 1057 * Opens the string table files, creating them if necessary. 1058 */ 1059 static int kDepDbStrTabInit(KDEPDBINTSTRTAB *pStrTab, const char *pszFilenameBase) 1060 { 1061 size_t cchFilenameBase = strlen(pszFilenameBase); 1062 char szPath[4096]; 1063 int rc; 1064 1065 /* Basic member init, so kDepDbStrTabTerm always works. */ 1066 pStrTab->pHash = NULL; 1067 kDepDbFHInit(&pStrTab->hHash); 1068 pStrTab->pStrTab = NULL; 1069 kDepDbFHInit(&pStrTab->hStrTab); 1070 pStrTab->iStringAlloced = 0; 1071 1072 /* check the length. */ 1073 if (cchFilenameBase + sizeof(".strtab.hash") > sizeof(szPath)) 1074 return -1; 1075 1076 /* 1077 * Open the string table first. 1078 */ 1079 memcpy(szPath, pszFilenameBase, cchFilenameBase); 1080 memcpy(&szPath[cchFilenameBase], ".strtab", sizeof(".strtab")); 1081 rc = kDepDbFHOpen(&pStrTab->hStrTab, szPath, &fNew); 1082 1083 1084 } 1085
Note:
See TracChangeset
for help on using the changeset viewer.