dynahash.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:22k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * dynahash.c
  4.  *   dynamic hashing
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.23.2.1 1999/08/02 05:25:08 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15.  *
  16.  * Dynamic hashing, after CACM April 1988 pp 446-457, by Per-Ake Larson.
  17.  * Coded into C, with minor code improvements, and with hsearch(3) interface,
  18.  * by ejp@ausmelb.oz, Jul 26, 1988: 13:16;
  19.  * also, hcreate/hdestroy routines added to simulate hsearch(3).
  20.  *
  21.  * These routines simulate hsearch(3) and family, with the important
  22.  * difference that the hash table is dynamic - can grow indefinitely
  23.  * beyond its original size (as supplied to hcreate()).
  24.  *
  25.  * Performance appears to be comparable to that of hsearch(3).
  26.  * The 'source-code' options referred to in hsearch(3)'s 'man' page
  27.  * are not implemented; otherwise functionality is identical.
  28.  *
  29.  * Compilation controls:
  30.  * DEBUG controls some informative traces, mainly for debugging.
  31.  * HASH_STATISTICS causes HashAccesses and HashCollisions to be maintained;
  32.  * when combined with HASH_DEBUG, these are displayed by hdestroy().
  33.  *
  34.  * Problems & fixes to ejp@ausmelb.oz. WARNING: relies on pre-processor
  35.  * concatenation property, in probably unnecessary code 'optimisation'.
  36.  *
  37.  * Modified margo@postgres.berkeley.edu February 1990
  38.  * added multiple table interface
  39.  * Modified by sullivan@postgres.berkeley.edu April 1990
  40.  * changed ctl structure for shared memory
  41.  */
  42. #include <sys/types.h>
  43. #include "postgres.h"
  44. #include "utils/dynahash.h"
  45. #include "utils/hsearch.h"
  46. #include "utils/memutils.h"
  47. /*
  48.  * Fast MOD arithmetic, assuming that y is a power of 2 !
  49.  */
  50. #define MOD(x,y)    ((x) & ((y)-1))
  51. /*
  52.  * Private function prototypes
  53.  */
  54. static long *DynaHashAlloc(unsigned int size);
  55. static void DynaHashFree(Pointer ptr);
  56. static uint32 call_hash(HTAB *hashp, char *k);
  57. static SEG_OFFSET seg_alloc(HTAB *hashp);
  58. static int bucket_alloc(HTAB *hashp);
  59. static int dir_realloc(HTAB *hashp);
  60. static int expand_table(HTAB *hashp);
  61. static int hdefault(HTAB *hashp);
  62. static int init_htab(HTAB *hashp, int nelem);
  63. typedef long *((*dhalloc_ptr) ());
  64. #ifndef FRONTEND
  65. /* ----------------
  66.  * memory allocation routines
  67.  *
  68.  * for postgres: all hash elements have to be in
  69.  * the global cache context.  Otherwise the postgres
  70.  * garbage collector is going to corrupt them. -wei
  71.  *
  72.  * ??? the "cache" memory context is intended to store only
  73.  *    system cache information.  The user of the hashing
  74.  *    routines should specify which context to use or we
  75.  *    should create a separate memory context for these
  76.  *    hash routines.  For now I have modified this code to
  77.  *    do the latter -cim 1/19/91
  78.  * ----------------
  79.  */
  80. GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
  81. static long *
  82. DynaHashAlloc(unsigned int size)
  83. {
  84. if (!DynaHashCxt)
  85. DynaHashCxt = CreateGlobalMemory("DynaHash");
  86. return (long *)
  87. MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
  88. }
  89. static void
  90. DynaHashFree(Pointer ptr)
  91. {
  92. MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
  93. }
  94. #define MEM_ALLOC DynaHashAlloc
  95. #define MEM_FREE DynaHashFree
  96. #else /* FRONTEND */
  97. #define MEM_ALLOC palloc
  98. #define MEM_FREE pfree
  99. #endif  /* FRONTEND */
  100. /*
  101.  * pointer access macros.  Shared memory implementation cannot
  102.  * store pointers in the hash table data structures because
  103.  * pointer values will be different in different address spaces.
  104.  * these macros convert offsets to pointers and pointers to offsets.
  105.  * Shared memory need not be contiguous, but all addresses must be
  106.  * calculated relative to some offset (segbase).
  107.  */
  108. #define GET_SEG(hp,seg_num)
  109.   (SEGMENT) (((unsigned long) (hp)->segbase) + (hp)->dir[seg_num])
  110. #define GET_BUCKET(hp,bucket_offs)
  111.   (ELEMENT *) (((unsigned long) (hp)->segbase) + bucket_offs)
  112. #define MAKE_HASHOFFSET(hp,ptr)
  113.   ( ((unsigned long) ptr) - ((unsigned long) (hp)->segbase) )
  114. #if HASH_STATISTICS
  115. static long hash_accesses,
  116. hash_collisions,
  117. hash_expansions;
  118. #endif
  119. /************************** CREATE ROUTINES **********************/
  120. HTAB *
  121. hash_create(int nelem, HASHCTL *info, int flags)
  122. {
  123. HHDR    *hctl;
  124. HTAB    *hashp;
  125. hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
  126. MemSet(hashp, 0, sizeof(HTAB));
  127. if (flags & HASH_FUNCTION)
  128. hashp->hash = info->hash;
  129. else
  130. {
  131. /* default */
  132. hashp->hash = string_hash;
  133. }
  134. if (flags & HASH_SHARED_MEM)
  135. {
  136. /*
  137.  * ctl structure is preallocated for shared memory tables. Note
  138.  * that HASH_DIRSIZE had better be set as well.
  139.  */
  140. hashp->hctl = (HHDR *) info->hctl;
  141. hashp->segbase = (char *) info->segbase;
  142. hashp->alloc = info->alloc;
  143. hashp->dir = (SEG_OFFSET *) info->dir;
  144. /* hash table already exists, we're just attaching to it */
  145. if (flags & HASH_ATTACH)
  146. return hashp;
  147. }
  148. else
  149. {
  150. /* setup hash table defaults */
  151. hashp->hctl = NULL;
  152. hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
  153. hashp->dir = NULL;
  154. hashp->segbase = NULL;
  155. }
  156. if (!hashp->hctl)
  157. {
  158. hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
  159. if (!hashp->hctl)
  160. return 0;
  161. }
  162. if (!hdefault(hashp))
  163. return 0;
  164. hctl = hashp->hctl;
  165. #ifdef HASH_STATISTICS
  166. hctl->accesses = hctl->collisions = 0;
  167. #endif
  168. if (flags & HASH_SEGMENT)
  169. {
  170. hctl->ssize = info->ssize;
  171. hctl->sshift = my_log2(info->ssize);
  172. /* ssize had better be a power of 2 */
  173. Assert(hctl->ssize == (1L << hctl->sshift));
  174. }
  175. if (flags & HASH_FFACTOR)
  176. hctl->ffactor = info->ffactor;
  177. /*
  178.  * SHM hash tables have fixed directory size passed by the caller.
  179.  */
  180. if (flags & HASH_DIRSIZE)
  181. {
  182. hctl->max_dsize = info->max_dsize;
  183. hctl->dsize = info->dsize;
  184. }
  185. /*
  186.  * hash table now allocates space for key and data but you have to say
  187.  * how much space to allocate
  188.  */
  189. if (flags & HASH_ELEM)
  190. {
  191. hctl->keysize = info->keysize;
  192. hctl->datasize = info->datasize;
  193. }
  194. if (flags & HASH_ALLOC)
  195. hashp->alloc = info->alloc;
  196. if (init_htab(hashp, nelem))
  197. {
  198. hash_destroy(hashp);
  199. return 0;
  200. }
  201. return hashp;
  202. }
  203. /*
  204.  * Set default HHDR parameters.
  205.  */
  206. static int
  207. hdefault(HTAB *hashp)
  208. {
  209. HHDR    *hctl;
  210. MemSet(hashp->hctl, 0, sizeof(HHDR));
  211. hctl = hashp->hctl;
  212. hctl->ssize = DEF_SEGSIZE;
  213. hctl->sshift = DEF_SEGSIZE_SHIFT;
  214. hctl->dsize = DEF_DIRSIZE;
  215. hctl->ffactor = DEF_FFACTOR;
  216. hctl->nkeys = 0;
  217. hctl->nsegs = 0;
  218. /* I added these MS. */
  219. /* default memory allocation for hash buckets */
  220. hctl->keysize = sizeof(char *);
  221. hctl->datasize = sizeof(char *);
  222. /* table has no fixed maximum size */
  223. hctl->max_dsize = NO_MAX_DSIZE;
  224. /* garbage collection for HASH_REMOVE */
  225. hctl->freeBucketIndex = INVALID_INDEX;
  226. return 1;
  227. }
  228. static int
  229. init_htab(HTAB *hashp, int nelem)
  230. {
  231. SEG_OFFSET *segp;
  232. int nbuckets;
  233. int nsegs;
  234. HHDR    *hctl;
  235. hctl = hashp->hctl;
  236. /*
  237.  * Divide number of elements by the fill factor to determine a desired
  238.  * number of buckets.  Allocate space for the next greater power of
  239.  * two number of buckets
  240.  */
  241. nelem = (nelem - 1) / hctl->ffactor + 1;
  242. nbuckets = 1 << my_log2(nelem);
  243. hctl->max_bucket = hctl->low_mask = nbuckets - 1;
  244. hctl->high_mask = (nbuckets << 1) - 1;
  245. /*
  246.  * Figure number of directory segments needed, round up to a power of
  247.  * 2
  248.  */
  249. nsegs = (nbuckets - 1) / hctl->ssize + 1;
  250. nsegs = 1 << my_log2(nsegs);
  251. /*
  252.  * Make sure directory is big enough. If pre-allocated directory is
  253.  * too small, choke (caller screwed up).
  254.  */
  255. if (nsegs > hctl->dsize)
  256. {
  257. if (!(hashp->dir))
  258. hctl->dsize = nsegs;
  259. else
  260. return -1;
  261. }
  262. /* Allocate a directory */
  263. if (!(hashp->dir))
  264. {
  265. hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
  266. if (!hashp->dir)
  267. return -1;
  268. }
  269. /* Allocate initial segments */
  270. for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
  271. {
  272. *segp = seg_alloc(hashp);
  273. if (*segp == (SEG_OFFSET) 0)
  274. {
  275. hash_destroy(hashp);
  276. return 0;
  277. }
  278. }
  279. #if HASH_DEBUG
  280. fprintf(stderr, "%sn%s%xn%s%dn%s%dn%s%dn%s%dn%s%dn%s%xn%s%xn%s%dn%s%dn",
  281. "init_htab:",
  282. "TABLE POINTER   ", hashp,
  283. "DIRECTORY SIZE  ", hctl->dsize,
  284. "SEGMENT SIZE    ", hctl->ssize,
  285. "SEGMENT SHIFT   ", hctl->sshift,
  286. "FILL FACTOR     ", hctl->ffactor,
  287. "MAX BUCKET      ", hctl->max_bucket,
  288. "HIGH MASK       ", hctl->high_mask,
  289. "LOW  MASK       ", hctl->low_mask,
  290. "NSEGS           ", hctl->nsegs,
  291. "NKEYS           ", hctl->nkeys);
  292. #endif
  293. return 0;
  294. }
  295. /*
  296.  * Estimate the space needed for a hashtable containing the given number
  297.  * of entries of given size.
  298.  * NOTE: this is used to estimate the footprint of hashtables in shared
  299.  * memory; therefore it does not count HTAB which is in local memory.
  300.  * NB: assumes that all hash structure parameters have default values!
  301.  */
  302. long
  303. hash_estimate_size(long num_entries, long keysize, long datasize)
  304. {
  305. long size = 0;
  306. long nBuckets,
  307. nSegments,
  308. nDirEntries,
  309. nRecordAllocs,
  310. recordSize;
  311. /* estimate number of buckets wanted */
  312. nBuckets = 1L << my_log2((num_entries - 1) / DEF_FFACTOR + 1);
  313. /* # of segments needed for nBuckets */
  314. nSegments = 1L << my_log2((nBuckets - 1) / DEF_SEGSIZE + 1);
  315. /* directory entries */
  316. nDirEntries = DEF_DIRSIZE;
  317. while (nDirEntries < nSegments)
  318. nDirEntries <<= 1; /* dir_alloc doubles dsize at each call */
  319. /* fixed control info */
  320. size += MAXALIGN(sizeof(HHDR)); /* but not HTAB, per above */
  321. /* directory */
  322. size += MAXALIGN(nDirEntries * sizeof(SEG_OFFSET));
  323. /* segments */
  324. size += nSegments * MAXALIGN(DEF_SEGSIZE * sizeof(BUCKET_INDEX));
  325. /* records --- allocated in groups of BUCKET_ALLOC_INCR */
  326. recordSize = sizeof(BUCKET_INDEX) + keysize + datasize;
  327. recordSize = MAXALIGN(recordSize);
  328. nRecordAllocs = (num_entries - 1) / BUCKET_ALLOC_INCR + 1;
  329. size += nRecordAllocs * BUCKET_ALLOC_INCR * recordSize;
  330. return size;
  331. }
  332. /********************** DESTROY ROUTINES ************************/
  333. /*
  334.  * XXX this sure looks thoroughly broken to me --- tgl 2/99.
  335.  * It's freeing every entry individually --- but they weren't
  336.  * allocated individually, see bucket_alloc!!  Why doesn't it crash?
  337.  * ANSWER: it probably does crash, but is never invoked in normal
  338.  * operations...
  339.  */
  340. void
  341. hash_destroy(HTAB *hashp)
  342. {
  343. if (hashp != NULL)
  344. {
  345. SEG_OFFSET segNum;
  346. SEGMENT segp;
  347. int nsegs = hashp->hctl->nsegs;
  348. int j;
  349. BUCKET_INDEX *elp,
  350. p,
  351. q;
  352. ELEMENT    *curr;
  353. /* cannot destroy a shared memory hash table */
  354. Assert(!hashp->segbase);
  355. /* allocation method must be one we know how to free, too */
  356. Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
  357. hash_stats("destroy", hashp);
  358. for (segNum = 0; nsegs > 0; nsegs--, segNum++)
  359. {
  360. segp = GET_SEG(hashp, segNum);
  361. for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++)
  362. {
  363. for (p = *elp; p != INVALID_INDEX; p = q)
  364. {
  365. curr = GET_BUCKET(hashp, p);
  366. q = curr->next;
  367. MEM_FREE((char *) curr);
  368. }
  369. }
  370. MEM_FREE((char *) segp);
  371. }
  372. MEM_FREE((char *) hashp->dir);
  373. MEM_FREE((char *) hashp->hctl);
  374. MEM_FREE((char *) hashp);
  375. }
  376. }
  377. void
  378. hash_stats(char *where, HTAB *hashp)
  379. {
  380. #if HASH_STATISTICS
  381. fprintf(stderr, "%s: this HTAB -- accesses %ld collisions %ldn",
  382. where, hashp->hctl->accesses, hashp->hctl->collisions);
  383. fprintf(stderr, "hash_stats: keys %ld keysize %ld maxp %d segmentcount %dn",
  384. hashp->hctl->nkeys, hashp->hctl->keysize,
  385. hashp->hctl->max_bucket, hashp->hctl->nsegs);
  386. fprintf(stderr, "%s: total accesses %ld total collisions %ldn",
  387. where, hash_accesses, hash_collisions);
  388. fprintf(stderr, "hash_stats: total expansions %ldn",
  389. hash_expansions);
  390. #endif
  391. }
  392. /*******************************SEARCH ROUTINES *****************************/
  393. static uint32
  394. call_hash(HTAB *hashp, char *k)
  395. {
  396. HHDR    *hctl = hashp->hctl;
  397. long hash_val,
  398. bucket;
  399. hash_val = hashp->hash(k, (int) hctl->keysize);
  400. bucket = hash_val & hctl->high_mask;
  401. if (bucket > hctl->max_bucket)
  402. bucket = bucket & hctl->low_mask;
  403. return bucket;
  404. }
  405. /*
  406.  * hash_search -- look up key in table and perform action
  407.  *
  408.  * action is one of HASH_FIND/HASH_ENTER/HASH_REMOVE
  409.  *
  410.  * RETURNS: NULL if table is corrupted, a pointer to the element
  411.  * found/removed/entered if applicable, TRUE otherwise.
  412.  * foundPtr is TRUE if we found an element in the table
  413.  * (FALSE if we entered one).
  414.  */
  415. long *
  416. hash_search(HTAB *hashp,
  417. char *keyPtr,
  418. HASHACTION action, /* HASH_FIND / HASH_ENTER / HASH_REMOVE
  419.  * HASH_FIND_SAVE / HASH_REMOVE_SAVED */
  420. bool *foundPtr)
  421. {
  422. uint32 bucket;
  423. long segment_num;
  424. long segment_ndx;
  425. SEGMENT segp;
  426. ELEMENT    *curr;
  427. HHDR    *hctl;
  428. BUCKET_INDEX currIndex;
  429. BUCKET_INDEX *prevIndexPtr;
  430. char    *destAddr;
  431. static struct State
  432. {
  433. ELEMENT    *currElem;
  434. BUCKET_INDEX currIndex;
  435. BUCKET_INDEX *prevIndex;
  436. } saveState;
  437. Assert((hashp && keyPtr));
  438. Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED));
  439. hctl = hashp->hctl;
  440. #if HASH_STATISTICS
  441. hash_accesses++;
  442. hashp->hctl->accesses++;
  443. #endif
  444. if (action == HASH_REMOVE_SAVED)
  445. {
  446. curr = saveState.currElem;
  447. currIndex = saveState.currIndex;
  448. prevIndexPtr = saveState.prevIndex;
  449. /*
  450.  * Try to catch subsequent errors
  451.  */
  452. Assert(saveState.currElem && !(saveState.currElem = 0));
  453. }
  454. else
  455. {
  456. bucket = call_hash(hashp, keyPtr);
  457. segment_num = bucket >> hctl->sshift;
  458. segment_ndx = MOD(bucket, hctl->ssize);
  459. segp = GET_SEG(hashp, segment_num);
  460. Assert(segp);
  461. prevIndexPtr = &segp[segment_ndx];
  462. currIndex = *prevIndexPtr;
  463. /*
  464.  * Follow collision chain
  465.  */
  466. for (curr = NULL; currIndex != INVALID_INDEX;)
  467. {
  468. /* coerce bucket index into a pointer */
  469. curr = GET_BUCKET(hashp, currIndex);
  470. if (!memcmp((char *) &(curr->key), keyPtr, hctl->keysize))
  471. break;
  472. prevIndexPtr = &(curr->next);
  473. currIndex = *prevIndexPtr;
  474. #if HASH_STATISTICS
  475. hash_collisions++;
  476. hashp->hctl->collisions++;
  477. #endif
  478. }
  479. }
  480. /*
  481.  * if we found an entry or if we weren't trying to insert, we're done
  482.  * now.
  483.  */
  484. *foundPtr = (bool) (currIndex != INVALID_INDEX);
  485. switch (action)
  486. {
  487. case HASH_ENTER:
  488. if (currIndex != INVALID_INDEX)
  489. return &(curr->key);
  490. break;
  491. case HASH_REMOVE:
  492. case HASH_REMOVE_SAVED:
  493. if (currIndex != INVALID_INDEX)
  494. {
  495. Assert(hctl->nkeys > 0);
  496. hctl->nkeys--;
  497. /* remove record from hash bucket's chain. */
  498. *prevIndexPtr = curr->next;
  499. /* add the record to the freelist for this table.  */
  500. curr->next = hctl->freeBucketIndex;
  501. hctl->freeBucketIndex = currIndex;
  502. /*
  503.  * better hope the caller is synchronizing access to this
  504.  * element, because someone else is going to reuse it the
  505.  * next time something is added to the table
  506.  */
  507. return &(curr->key);
  508. }
  509. return (long *) TRUE;
  510. case HASH_FIND:
  511. if (currIndex != INVALID_INDEX)
  512. return &(curr->key);
  513. return (long *) TRUE;
  514. case HASH_FIND_SAVE:
  515. if (currIndex != INVALID_INDEX)
  516. {
  517. saveState.currElem = curr;
  518. saveState.prevIndex = prevIndexPtr;
  519. saveState.currIndex = currIndex;
  520. return &(curr->key);
  521. }
  522. return (long *) TRUE;
  523. default:
  524. /* can't get here */
  525. return NULL;
  526. }
  527. /*
  528.  * If we got here, then we didn't find the element and we have to
  529.  * insert it into the hash table
  530.  */
  531. Assert(currIndex == INVALID_INDEX);
  532. /* get the next free bucket */
  533. currIndex = hctl->freeBucketIndex;
  534. if (currIndex == INVALID_INDEX)
  535. {
  536. /* no free elements.  allocate another chunk of buckets */
  537. if (!bucket_alloc(hashp))
  538. return NULL;
  539. currIndex = hctl->freeBucketIndex;
  540. }
  541. Assert(currIndex != INVALID_INDEX);
  542. curr = GET_BUCKET(hashp, currIndex);
  543. hctl->freeBucketIndex = curr->next;
  544. /* link into chain */
  545. *prevIndexPtr = currIndex;
  546. /* copy key into record */
  547. destAddr = (char *) &(curr->key);
  548. memmove(destAddr, keyPtr, hctl->keysize);
  549. curr->next = INVALID_INDEX;
  550. /*
  551.  * let the caller initialize the data field after hash_search returns.
  552.  */
  553. /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize); */
  554. /*
  555.  * Check if it is time to split the segment
  556.  */
  557. if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor)
  558. {
  559. /*
  560.  * NOTE: failure to expand table is not a fatal error, it just
  561.  * means we have to run at higher fill factor than we wanted.
  562.  */
  563. expand_table(hashp);
  564. }
  565. return &(curr->key);
  566. }
  567. /*
  568.  * hash_seq -- sequentially search through hash table and return
  569.  *    all the elements one by one, return NULL on error and
  570.  *    return TRUE in the end.
  571.  *
  572.  */
  573. long *
  574. hash_seq(HTAB *hashp)
  575. {
  576. static uint32 curBucket = 0;
  577. static BUCKET_INDEX curIndex;
  578. ELEMENT    *curElem;
  579. long segment_num;
  580. long segment_ndx;
  581. SEGMENT segp;
  582. HHDR    *hctl;
  583. if (hashp == NULL)
  584. {
  585. /*
  586.  * reset static state
  587.  */
  588. curBucket = 0;
  589. curIndex = INVALID_INDEX;
  590. return (long *) NULL;
  591. }
  592. hctl = hashp->hctl;
  593. while (curBucket <= hctl->max_bucket)
  594. {
  595. if (curIndex != INVALID_INDEX)
  596. {
  597. curElem = GET_BUCKET(hashp, curIndex);
  598. curIndex = curElem->next;
  599. if (curIndex == INVALID_INDEX) /* end of this bucket */
  600. ++curBucket;
  601. return &(curElem->key);
  602. }
  603. /*
  604.  * initialize the search within this bucket.
  605.  */
  606. segment_num = curBucket >> hctl->sshift;
  607. segment_ndx = MOD(curBucket, hctl->ssize);
  608. /*
  609.  * first find the right segment in the table directory.
  610.  */
  611. segp = GET_SEG(hashp, segment_num);
  612. if (segp == NULL)
  613. /* this is probably an error */
  614. return (long *) NULL;
  615. /*
  616.  * now find the right index into the segment for the first item in
  617.  * this bucket's chain.  if the bucket is not empty (its entry in
  618.  * the dir is valid), we know this must correspond to a valid
  619.  * element and not a freed element because it came out of the
  620.  * directory of valid stuff.  if there are elements in the bucket
  621.  * chains that point to the freelist we're in big trouble.
  622.  */
  623. curIndex = segp[segment_ndx];
  624. if (curIndex == INVALID_INDEX) /* empty bucket */
  625. ++curBucket;
  626. }
  627. return (long *) TRUE; /* out of buckets */
  628. }
  629. /********************************* UTILITIES ************************/
  630. /*
  631.  * Expand the table by adding one more hash bucket.
  632.  */
  633. static int
  634. expand_table(HTAB *hashp)
  635. {
  636. HHDR    *hctl;
  637. SEGMENT old_seg,
  638. new_seg;
  639. long old_bucket,
  640. new_bucket;
  641. long new_segnum,
  642. new_segndx;
  643. long old_segnum,
  644. old_segndx;
  645. ELEMENT    *chain;
  646. BUCKET_INDEX *old,
  647.    *newbi;
  648. BUCKET_INDEX chainIndex,
  649. nextIndex;
  650. #ifdef HASH_STATISTICS
  651. hash_expansions++;
  652. #endif
  653. hctl = hashp->hctl;
  654. new_bucket = hctl->max_bucket + 1;
  655. new_segnum = new_bucket >> hctl->sshift;
  656. new_segndx = MOD(new_bucket, hctl->ssize);
  657. if (new_segnum >= hctl->nsegs)
  658. {
  659. /* Allocate new segment if necessary -- could fail if dir full */
  660. if (new_segnum >= hctl->dsize)
  661. if (!dir_realloc(hashp))
  662. return 0;
  663. if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
  664. return 0;
  665. hctl->nsegs++;
  666. }
  667. /* OK, we created a new bucket */
  668. hctl->max_bucket++;
  669. /*
  670.  * *Before* changing masks, find old bucket corresponding to same hash
  671.  * values; values in that bucket may need to be relocated to new bucket.
  672.  * Note that new_bucket is certainly larger than low_mask at this point,
  673.  * so we can skip the first step of the regular hash mask calc.
  674.  */
  675. old_bucket = (new_bucket & hctl->low_mask);
  676. /*
  677.  * If we crossed a power of 2, readjust masks.
  678.  */
  679. if (new_bucket > hctl->high_mask)
  680. {
  681. hctl->low_mask = hctl->high_mask;
  682. hctl->high_mask = new_bucket | hctl->low_mask;
  683. }
  684. /*
  685.  * Relocate records to the new bucket.  NOTE: because of the way the
  686.  * hash masking is done in call_hash, only one old bucket can need to
  687.  * be split at this point.  With a different way of reducing the hash
  688.  * value, that might not be true!
  689.  */
  690. old_segnum = old_bucket >> hctl->sshift;
  691. old_segndx = MOD(old_bucket, hctl->ssize);
  692. old_seg = GET_SEG(hashp, old_segnum);
  693. new_seg = GET_SEG(hashp, new_segnum);
  694. old = &old_seg[old_segndx];
  695. newbi = &new_seg[new_segndx];
  696. for (chainIndex = *old;
  697.  chainIndex != INVALID_INDEX;
  698.  chainIndex = nextIndex)
  699. {
  700. chain = GET_BUCKET(hashp, chainIndex);
  701. nextIndex = chain->next;
  702. if (call_hash(hashp, (char *) &(chain->key)) == old_bucket)
  703. {
  704. *old = chainIndex;
  705. old = &chain->next;
  706. }
  707. else
  708. {
  709. *newbi = chainIndex;
  710. newbi = &chain->next;
  711. }
  712. }
  713. /* don't forget to terminate the rebuilt hash chains... */
  714. *old = INVALID_INDEX;
  715. *newbi = INVALID_INDEX;
  716. return 1;
  717. }
  718. static int
  719. dir_realloc(HTAB *hashp)
  720. {
  721. char    *p;
  722. char    *old_p;
  723. long new_dsize;
  724. long old_dirsize;
  725. long new_dirsize;
  726. if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
  727. return 0;
  728. /* Reallocate directory */
  729. new_dsize = hashp->hctl->dsize << 1;
  730. old_dirsize = hashp->hctl->dsize * sizeof(SEG_OFFSET);
  731. new_dirsize = new_dsize * sizeof(SEG_OFFSET);
  732. old_p = (char *) hashp->dir;
  733. p = (char *) hashp->alloc((unsigned long) new_dirsize);
  734. if (p != NULL)
  735. {
  736. memmove(p, old_p, old_dirsize);
  737. MemSet(p + old_dirsize, 0, new_dirsize - old_dirsize);
  738. MEM_FREE((char *) old_p);
  739. hashp->dir = (SEG_OFFSET *) p;
  740. hashp->hctl->dsize = new_dsize;
  741. return 1;
  742. }
  743. return 0;
  744. }
  745. static SEG_OFFSET
  746. seg_alloc(HTAB *hashp)
  747. {
  748. SEGMENT segp;
  749. SEG_OFFSET segOffset;
  750. segp = (SEGMENT) hashp->alloc((unsigned long)
  751.   sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
  752. if (!segp)
  753. return 0;
  754. MemSet((char *) segp, 0,
  755.    (long) sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
  756. segOffset = MAKE_HASHOFFSET(hashp, segp);
  757. return segOffset;
  758. }
  759. /*
  760.  * allocate some new buckets and link them into the free list
  761.  */
  762. static int
  763. bucket_alloc(HTAB *hashp)
  764. {
  765. int i;
  766. ELEMENT    *tmpBucket;
  767. long bucketSize;
  768. BUCKET_INDEX tmpIndex,
  769. lastIndex;
  770. /* Each bucket has a BUCKET_INDEX header plus user data. */
  771. bucketSize = sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
  772. /* make sure its aligned correctly */
  773. bucketSize = MAXALIGN(bucketSize);
  774. tmpBucket = (ELEMENT *)
  775. hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
  776. if (!tmpBucket)
  777. return 0;
  778. /* tmpIndex is the shmem offset into the first bucket of the array */
  779. tmpIndex = MAKE_HASHOFFSET(hashp, tmpBucket);
  780. /* set the freebucket list to point to the first bucket */
  781. lastIndex = hashp->hctl->freeBucketIndex;
  782. hashp->hctl->freeBucketIndex = tmpIndex;
  783. /*
  784.  * initialize each bucket to point to the one behind it. NOTE: loop
  785.  * sets last bucket incorrectly; we fix below.
  786.  */
  787. for (i = 0; i < BUCKET_ALLOC_INCR; i++)
  788. {
  789. tmpBucket = GET_BUCKET(hashp, tmpIndex);
  790. tmpIndex += bucketSize;
  791. tmpBucket->next = tmpIndex;
  792. }
  793. /*
  794.  * the last bucket points to the old freelist head (which is probably
  795.  * invalid or we wouldn't be here)
  796.  */
  797. tmpBucket->next = lastIndex;
  798. return 1;
  799. }
  800. /* calculate ceil(log base 2) of num */
  801. int
  802. my_log2(long num)
  803. {
  804. int i;
  805. long limit;
  806. for (i = 0, limit = 1; limit < num; i++, limit <<= 1)
  807. ;
  808. return i;
  809. }