2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
18 #include <netinet/in.h>
20 #include <sys/types.h>
24 #include <afs/bubasics.h>
25 #include "budb_errs.h"
27 #include "error_macros.h"
30 int sizeFunctions[HT_MAX_FUNCTION+1];
31 int nHTBuckets = NhtBucketS; /* testing: we need small HT blocks */
33 /* ht_TableSize - return the size of table necessary to represent a hashtable
34 * of given length in memory. It basically rounds the length up by the number
35 * of buckets per block. */
37 int ht_TableSize (length)
40 if (length == 0) return 0;
41 n = (length + nHTBuckets-1) / nHTBuckets;
42 return n*sizeof(struct memoryHTBlock *);
45 /* ht_ResetT - resets the in-memory representation of a hashtable block array.
46 * It also resets the global variable nHTBuckets. */
48 static void ht_ResetT (blocksP, sizeP, length)
49 struct memoryHTBlock ***blocksP;
52 { struct memoryHTBlock **b = *blocksP;
57 nHTBuckets = ntohl(db.h.nHTBuckets);
59 n = *sizeP / sizeof(b[0]);
60 newsize = ht_TableSize (length);
61 if (*sizeP != newsize) {
62 /* free all blocks in the old array */
64 if (b[i]) free (b[i]);
69 /* invalidate the blocks of the array */
71 if (b[i]) b[i]->valid = 0;
77 * reinitialize a memory hash table.
78 * Calls ht_ResetT to invalidate the two block arrays.
82 struct memoryHashTable *mht;
83 { struct hashTable *ht;
85 if (!(mht && (ht = mht->ht)))
86 db_panic ("some ht called with bad mht");
87 mht->threadOffset = ntohl(ht->threadOffset);
88 mht->length = ntohl(ht->length);
89 mht->oldLength = ntohl(ht->oldLength);
90 mht->progress = ntohl(ht->progress);
91 ht_ResetT (&mht->blocks, &mht->size, mht->length);
92 ht_ResetT (&mht->oldBlocks, &mht->oldSize, mht->oldLength);
95 /* InitDBhash - When server starts, do hash table initialization.
96 test - initialization parameters: bit 4 is small ht. */
98 afs_int32 InitDBhash ()
100 sizeFunctions[0] = 0;
102 sizeFunctions[HT_dumpIden_FUNCTION] = sizeof(struct dump);
103 sizeFunctions[HT_dumpName_FUNCTION] = sizeof(struct dump);
104 sizeFunctions[HT_volName_FUNCTION] = sizeof(struct volInfo);
105 sizeFunctions[HT_tapeName_FUNCTION] = sizeof(struct tape);
107 db.volName.ht = &db.h.volName;
108 db.tapeName.ht = &db.h.tapeName;
109 db.dumpName.ht = &db.h.dumpName;
110 db.dumpIden.ht = &db.h.dumpIden;
114 /* ht_DBInit - When rebuilding database, this sets up the hash tables. */
118 db.h.nHTBuckets = htonl(nHTBuckets);
120 { struct volInfo *s = 0;
121 db.h.volName.threadOffset = htonl((char *)&s->nameHashChain - (char *)s);
122 db.h.volName.functionType = htonl(HT_volName_FUNCTION);
124 { struct tape *s = 0;
125 db.h.tapeName.threadOffset = htonl((char *)&s->nameHashChain - (char *)s);
126 db.h.tapeName.functionType = htonl(HT_tapeName_FUNCTION);
128 { struct dump *s = 0;
129 db.h.dumpName.threadOffset = htonl((char *)&s->nameHashChain - (char *)s);
130 db.h.dumpName.functionType = htonl(HT_dumpName_FUNCTION);
132 db.h.dumpIden.threadOffset = htonl((char *)&s->idHashChain - (char *)s);
133 db.h.dumpIden.functionType = htonl(HT_dumpIden_FUNCTION);
135 ht_Reset (&db.volName);
136 ht_Reset (&db.tapeName);
137 ht_Reset (&db.dumpName);
138 ht_Reset (&db.dumpIden);
141 afs_int32 ht_AllocTable (ut, mht)
142 struct ubik_trans *ut;
143 struct memoryHashTable *mht;
144 { struct hashTable *ht;
147 int nb, mnb; /* number of blocks for hashTable */
149 struct memoryHTBlock **b;
151 if (!(mht && (ht = mht->ht))) db_panic ("some ht called with bad mht");
152 if (ht->length || mht->blocks) db_panic ("previous table still allocated");
154 len = ntohl(ht->entries) * 2; /* allow room to grow */
155 nb = (len + nHTBuckets-1) / nHTBuckets;
156 mnb = ht_minHBlocks(mht);
157 if (nb < mnb) nb = mnb; /* use minimum */
158 len = nb * nHTBuckets; /* new hash table length */
160 mht->size = nb*sizeof(struct memoryHTBlock *);
161 b = mht->blocks = (struct memoryHTBlock **)malloc (mht->size);
162 bzero (b, mht->size);
164 for (i=0; i<nb; i++) {
165 b[i] = (struct memoryHTBlock *)malloc (sizeof (struct memoryHTBlock));
166 code = AllocBlock (ut, (struct block *)&b[i]->b, &b[i]->a);
167 if (code) return code;
170 b[i]->b.h.type = hashTable_BLOCK;
172 /* thread the blocks */
173 if (i) b[i-1]->b.h.next = htonl(b[i]->a);
177 code = dbwrite (ut, b[i]->a, (char *)&b[i]->b,
178 sizeof(struct htBlock) + (nHTBuckets-NhtBucketS)*sizeof(dbadr));
182 if (code = set_word_addr (ut, 0, &db.h, &ht->table, htonl(b[0]->a)))
185 if (code = set_word_addr (ut, 0, &db.h, &ht->length, htonl(len)))
191 afs_int32 ht_FreeTable (ut, mht)
192 struct ubik_trans *ut;
193 struct memoryHashTable *mht;
194 { struct hashTable *ht;
196 struct blockHeader bh;
199 if (!(mht && (ht = mht->ht))) db_panic ("some ht called with bad mht");
200 if (ht->oldLength == 0) db_panic ("no table to free");
202 ht_ResetT (&mht->oldBlocks, &mht->oldSize, 0);
204 for (a=ntohl(ht->oldTable); a; a=na) {
205 if (dbread (ut, a, (char *)&bh, sizeof(bh)))
207 Log("ht_FreeTable: dbread failed\n");
211 if (code = FreeBlock (ut, &bh, a)) return code;
213 if (set_word_addr (ut, 0, &db.h, &ht->oldTable, 0) ||
214 set_word_addr (ut, 0, &db.h, &ht->oldLength, 0) ||
215 set_word_addr (ut, 0, &db.h, &ht->progress, 0))
217 mht->oldLength = mht->progress = 0;
222 ht_GetTableBlock (ut, mht, hash, old, blockP, boP)
223 struct ubik_trans *ut;
224 struct memoryHashTable *mht;
227 struct memoryHTBlock **blockP;
230 struct hashTable *ht;
231 struct memoryHTBlock **b;
233 struct memoryHTBlock ***blocksP;
241 || ((ht = mht->ht) == 0)
244 db_panic ("some ht called with bad mht");
250 if ((length = mht->oldLength) == 0) return 0; /* no entries */
252 if (hi < mht->progress) return 0; /* no such entry */
253 blocksP = &mht->oldBlocks;
254 sizeP = &mht->oldSize;
256 if ((length = mht->length) == 0) return 0; /* no entries */
258 blocksP = &mht->blocks;
262 bi = hi / nHTBuckets; /* block index */
263 *boP = hi - bi*nHTBuckets; /* block offset ptr */
266 *sizeP = ht_TableSize (length);
267 *blocksP = (struct memoryHTBlock **)malloc (*sizeP);
268 bzero (*blocksP, *sizeP);
270 n = *sizeP / sizeof (struct memoryHTBlock *);
271 if (bi >= n) db_panic ("table size inconsistent");
274 /* find an allocated block or the beginning of the block array */
275 for (i=bi; (i>0) && (b[i] == 0); i--);
279 if (i == 0) { /* the first block is found from the hashTable */
280 ta = ntohl(old ? ht->oldTable : ht->table);
281 if (ta == 0) db_panic ("non-zero length, but no table");
283 /* else ta is set from last time around loop */
284 b[i] = (struct memoryHTBlock *)malloc (sizeof (struct memoryHTBlock));
290 if (dbread (ut, b[i]->a, (char *)&b[i]->b, sizeof(struct htBlock)))
298 /* printf("ht_GetTableBlock: hash %d block %d offset %d\n",
299 hash, *blockP, *boP); */
303 ta = ntohl(b[i++]->b.h.next); /* get next ptr from current block */
308 * Decide when to push the current hash table to the old hash table.
309 * The entries in the old hash table are VALID, and are slowly hashed
310 * into the current table.
314 ht_MaybeAdjust (ut, mht)
315 struct ubik_trans *ut;
316 struct memoryHashTable *mht;
318 struct hashTable *ht = mht->ht;
319 int numberEntries = ntohl(ht->entries);
321 /* old hash table must be empty */
322 if ( mht->oldLength != 0)
326 * It costs a lot to grow and shrink the hash table. Therefore, we will not
327 * shrink the hash table (only grow it). If the table is more than 2 entries per
328 * chain (average) we need to grow: push the entries to the old hash table.
331 * || ((mht->length > nHTBuckets) && (numberEntries*8 < mht->length))
334 /* Only grow a hash table if the number of entries is twice the
335 * number of hash length and is less than 20,450 (20 hash blocks). This
336 * means that the volname hash table will not grow (its initial
337 * hashtable size contains 30,600 buckets). Earlier revisions of
338 * the buserver have the initial size at 510 and 5,100 buckets -
339 * in which case we do want to grow it). We don't grow anything larger
340 * than 20,450 entries because it's expensive to re-hash everything.
342 if ((numberEntries > mht->length*2) && (numberEntries < 20450))
343 { /* push current hash table to old hash table */
344 ht->oldLength = ht->length;
345 ht->oldTable = ht->table;
349 if (dbwrite (ut, ((char *)ht - (char *)&db.h), (char *)ht, sizeof (*ht)))
353 LogDebug(2, "ht_MaybeAdjust: push ht to old\n");
358 dbadr ht_LookupBucket (ut, mht, hash, old)
359 struct ubik_trans *ut;
360 struct memoryHashTable *mht;
363 { struct memoryHTBlock *block;
367 if ((old ? mht->oldLength : mht->length) == 0) return 0;
368 code = ht_GetTableBlock (ut, mht, hash, old, &block, &bo);
369 if (code || (block == 0)) return 0;
370 return ntohl(block->b.bucket[bo]);
373 /* This function is not too bad, for small hash tables, but suffers, I think,
374 * from insufficient mixing of the hash information. */
376 afs_uint32 Old2StringHashFunction (str)
378 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
379 while (*str) hash = (hash<<1) + (hash>>31) + *str++;
383 /* This was actually a coding error, and produces dreadful results. The
384 * problem is that the hash needs to be mixed up not the incoming character. */
386 afs_uint32 Old3StringHashFunction (str)
388 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
389 while (*str) hash += (*str++) * 0x072a51a4;
393 /* This function is pretty good. Its main problem is that the low two bits of
394 * the hash multiplier are zero which tends to shift information too far left.
395 * It behaves especially badly for hash tables whose size is a power of two. */
397 afs_uint32 Old4StringHashFunction (str)
399 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
400 while (*str) hash = (*str++) + hash * 0x072a51a4;
404 /* While this is good for a hash table with 500 buckets it is nearly as bad as
405 * #3 with a hash table as big as 8200. */
407 afs_uint32 Old5StringHashFunction (str)
409 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
410 while (*str) hash += (*str++);
414 /* This was an attempt to produce a hash function with the smallest and
415 * simplest mixing multiplier. This is only a little worse than the real one,
416 * and the difference seems to be smaller with larger hash tables. It behaves
417 * better than the random hash function. */
419 afs_uint32 Old6StringHashFunction (str)
421 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
422 while (*str) hash = hash*0x81 + (*str++);
426 /* This actually seems to be little better then the real one. Having the same
427 * number of bits but only 5 bits apart seems to produce worse results but
428 * having the bits spanning the same range farther apart also doesn't do as
429 * well. All these differences are fairly small, however. */
431 afs_uint32 Old7StringHashFunction (str)
433 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
434 while (*str) hash = hash*0x42108421 + (*str++);
438 /* This function tries to provide some non-linearity by providing some feedback
439 * from higher-order bits in the word. It also uses shifts instead of
440 * multiplies, which may be faster on some architectures. */
442 afs_uint32 Old8StringHashFunction (str)
444 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
446 hash = hash + (hash<<7) + (hash<<14) + (hash<<21) + (hash<<28) +
451 /* This is the result of the above search for good hash functions. It seems
452 * that the choice of multipliers is somewhat arbitrary but has several
453 * constraints. It shouldn't have too many or too few one bits and should be
454 * odd. It behaves beeter than the random hash function. */
456 afs_uint32 StringHashFunction (str)
458 { afs_uint32 hash = 1000003; /* big prime to make "" hash nicely */
459 /* The multiplicative constant should be odd and have a goodly number of
461 while (*str) hash = (*str++) + hash * 0x10204081;
465 afs_uint32 IdHashFunction (id)
474 /* The minimum hash table blocks to allocate. Each block contains 510
475 * buckets. They hash table grows when the number of entries reaches
476 * twice the number of buckets.
478 int ht_minHBlocks(mht)
479 struct memoryHashTable *mht;
483 switch ( ntohl(mht->ht->functionType) )
485 case HT_dumpIden_FUNCTION:
486 case HT_dumpName_FUNCTION: /* hash table able to handle (befor it grows) ... */
487 retval = 2; /* 1,020 dump entries */
490 case HT_tapeName_FUNCTION:
491 retval = 4; /* 2,040 tape entries */
494 case HT_volName_FUNCTION:
495 retval = 60; /* 61,200 volInfo entries (with different names) */
498 default: db_panic ("Illegal hash function type");
503 afs_uint32 ht_HashEntry (mht, e)
504 struct memoryHashTable *mht;
505 char *e; /* entry's address (in b) */
507 int type = ntohl(mht->ht->functionType);
512 case HT_dumpIden_FUNCTION:
513 retval = IdHashFunction(ntohl(((struct dump *)e)->id));
514 LogDebug(5, "HashEntry: dumpid returns %d\n", retval);
517 case HT_dumpName_FUNCTION:
518 retval = StringHashFunction(((struct dump *)e)->dumpName);
519 LogDebug(5, "HashEntry: dumpname returns %d\n", retval);
522 case HT_tapeName_FUNCTION:
523 retval = StringHashFunction(((struct tape *)e)->name);
524 LogDebug(5, "HashEntry: tapename returns %d\n", retval);
527 case HT_volName_FUNCTION:
528 retval = StringHashFunction (((struct volInfo *)e)->name);
529 LogDebug(5, "HashEntry: volname returns %d\n", retval);
532 default: db_panic ("illegal hash function");
540 * returns a ptr to the memory hash table for the specified hash
544 struct memoryHashTable *
545 ht_GetType(type, e_sizeP)
549 struct memoryHashTable *mht;
551 if ((type <= 0) || (type > HT_MAX_FUNCTION))
554 if (e_sizeP) *e_sizeP = sizeFunctions[type];
557 case HT_dumpIden_FUNCTION:
561 case HT_dumpName_FUNCTION:
565 case HT_tapeName_FUNCTION:
569 case HT_volName_FUNCTION:
575 if (ntohl(mht->ht->functionType) != type)
576 db_panic ("ht types don't match");
580 static int ht_KeyMatch (type, key, e)
586 case HT_dumpIden_FUNCTION:
587 return *(dumpId *)key == ntohl(((struct dump *)e)->id);
588 case HT_dumpName_FUNCTION:
589 return strcmp (key, ((struct dump *)e)->dumpName) == 0;
590 case HT_tapeName_FUNCTION:
591 return strcmp (key, ((struct tape *)e)->name) == 0;
592 case HT_volName_FUNCTION:
593 return strcmp (key, ((struct volInfo *)e)->name) == 0;
595 default: db_panic ("illegal hash function");
601 * ut - ubik transaction
602 * mht - memory hash table ptr
603 * key - hash and lookup key
605 * eaP - dbaddr of entry found or zero if failed
606 * e - contents of located entry
610 ht_LookupEntry (ut, mht, key, eaP, e)
611 struct ubik_trans *ut;
612 struct memoryHashTable *mht;
613 char *key; /* pointer to lookup key to match */
614 dbadr *eaP; /* db addr of entry found or zero */
615 char *e; /* contents of located entry */
616 { struct hashTable *ht;
623 if (!key || !eaP || !e) db_panic ("null ptrs passed to LookupEntry");
624 if (!(mht && (ht = mht->ht))) db_panic ("some ht called with bad mht");
626 *eaP = 0; /* initialize not-found indicator */
628 type = ntohl(ht->functionType);
629 e_size = sizeFunctions[type];
630 if (type == HT_dumpIden_FUNCTION)
631 hash = IdHashFunction (*(dumpId *)key);
633 hash = StringHashFunction (key);
637 a = ht_LookupBucket (ut, mht, hash, old);
639 if (dbread (ut, a, e, e_size))
641 if (ht_KeyMatch (type, key, e))
646 a = ntohl(*(dbadr *)(e + mht->threadOffset));
654 * opQuota - max # of items to move
656 * opQuota - adjusted to reflect # of moves
659 static afs_int32 ht_HashInList (ut, mht, opQuota, block, blockOffset)
660 struct ubik_trans *ut;
661 struct memoryHashTable *mht;
663 struct memoryHTBlock *block;
666 struct hashTable *ht = mht->ht;
670 char e[sizeof(struct block)]; /* unnecessarily conservative */
671 int e_size = sizeFunctions[ntohl(ht->functionType)];
673 if (mht->length == 0)
675 if (code = ht_AllocTable (ut, mht))
677 Log("ht_HashInList: ht_AllocTable failed\n");
682 listA = ntohl(block->b.bucket[blockOffset]);
686 Log("ht_HashInList: expecting non-zero bucket\n");
690 for (ea=listA; ea; ea=next_ea)
693 LogDebug(3, "ht_HashInList: move entry at %d, type %d\n",
694 ea, ntohl(mht->ht->functionType));
696 if (dbread (ut, ea, e, e_size))
699 /* LogNetDump((struct dump *) e); */
701 /* get the address of the next item on the list */
702 next_ea = ntohl(*(dbadr *)(e + mht->threadOffset));
704 /* write the link into the bucket */
705 code = set_word_addr (ut, block->a, &block->b, &block->b.bucket[blockOffset],
709 Log("ht_HashInList: bucket update failed\n");
713 { struct memoryHTBlock *block;
717 /* get the hash value */
718 hash = ht_HashEntry (mht, e) % mht->length;
719 LogDebug(4, "ht_HashInList: moved to %d\n", hash);
721 /* get the new hash table block */
722 code = ht_GetTableBlock (ut, mht, hash, 0/*old*/, &block, &bo);
725 Log("ht_HashInList: ht_GetTableBlock failed\n");
730 Log("ht_HashInList: ht_GetTableBlock returned 0\n");
731 return BUDB_INTERNALERROR;
734 /* Chain entry at front of bucket;
735 * first threadOffset of entry = bucket
736 * then bucket = addr of entry
738 if (set_word_offset (ut, ea, e, mht->threadOffset, block->b.bucket[bo]) ||
739 set_word_addr (ut, block->a, &block->b, &block->b.bucket[bo], htonl(ea)))
743 if ( --(*opQuota) == 0 )
751 * The hash table is needs to be re-sized. Move entries from the old
756 ht_MoveEntries(ut, mht)
757 struct ubik_trans *ut;
758 struct memoryHashTable *mht;
760 struct memoryHTBlock *block;
766 if (mht->oldLength == 0)
769 LogDebug(3, "ht_MoveEntries:\n");
770 /* we assume here that the hash function will map numbers smaller than the
771 * size of the hash table straight through to hash table indexes.
773 hash = mht->progress;
775 /* get hash table block ? */
776 code = ht_GetTableBlock (ut, mht, hash, 1 /*old*/, &block, &bo);
781 return BUDB_INTERNALERROR;
783 count = 10; /* max. # entries to move */
786 if (block->b.bucket[bo])
788 code = ht_HashInList(ut, mht, &count, block, bo);
791 Log("ht_MoveEntries: ht_HashInList failed\n");
796 if (block->b.bucket[bo] == 0)
798 /* this bucket is now empty */
802 /* don't exceed the quota of items to be moved */
806 } while (++bo < nHTBuckets);
808 if (mht->progress >= mht->oldLength)
809 return( ht_FreeTable (ut, mht) );
811 if (set_word_addr (ut, 0, &db.h, &mht->ht->progress, htonl(mht->progress)))
813 Log("ht_MoveEntries: progress set failed\n");
822 ht_MoveEntries(ut, mht)
823 struct ubik_trans *ut;
824 struct memoryHashTable *mht;
828 struct memoryHTBlock *block;
831 if (mht->oldLength == 0)
834 LogDebug(3, "ht_MoveEntries:\n");
835 /* we assume here that the hash function will map numbers smaller than the
836 * size of the hash table straight through to hash table indexes.
838 hash = mht->progress;
840 /* get hash table block ? */
841 code = ht_GetTableBlock (ut, mht, hash, 1 /*old*/, &block, &bo);
846 return BUDB_INTERNALERROR;
850 if (block->b.bucket[bo])
852 code = ht_HashInList(ut, mht, ntohl(block->b.bucket[bo]));
855 Log("ht_MoveEntries: ht_HashInList failed\n");
858 code = set_word_addr(ut, block->a, &block->b, &block->b.bucket[bo], 0);
861 Log("ht_MoveEntries: clear old entry failed\n");
866 } while (++bo < nHTBuckets);
868 if (mht->progress >= mht->oldLength)
869 return( ht_FreeTable (ut, mht) );
871 if (set_word_addr (ut, 0, &db.h, &mht->ht->progress, htonl(mht->progress)))
873 Log("ht_MoveEntries: progress set failed\n");
881 ht_HashIn(ut, mht, ea, e)
882 struct ubik_trans *ut;
883 struct memoryHashTable *mht;
884 dbadr ea; /* block db address */
885 char *e; /* entry's address (in b) */
887 struct hashTable *ht;
889 struct memoryHTBlock *block;
893 if (!(mht && (ht = mht->ht)))
894 db_panic("some ht called with bad mht");
896 if (code = ht_MaybeAdjust (ut, mht))
898 if (mht->length == 0)
899 if (code = ht_AllocTable (ut, mht))
902 hash = ht_HashEntry (mht, e);
903 code = ht_GetTableBlock (ut, mht, hash, 0/*old*/, &block, &bo);
904 if (code) return code;
905 if (!block) return BUDB_INTERNALERROR;
907 code = set_word_offset(ut, ea, e, mht->threadOffset, block->b.bucket[bo]);
908 if (code) return BUDB_IO;
909 LogDebug(5, "Hashin: set %d to %d\n", mht->threadOffset, block->b.bucket[bo]);
911 code = set_word_addr (ut, block->a, &block->b, &block->b.bucket[bo], htonl(ea));
912 if (code) return BUDB_IO;
913 LogDebug(5, "Hashin: set %d to %d\n", &block->b.bucket[bo], htonl(ea));
915 code = set_word_addr (ut, 0, &db.h, &ht->entries, htonl(ntohl(ht->entries)+1));
916 if (code) return BUDB_IO;
918 return ht_MoveEntries (ut, mht);
921 /* RemoveFromList - generic procedure to delete an entry from a list given its
922 * head and thread offset. Only a single long is modified by this routine.
923 * The head pointer is modified, in place, using set_word_addr if the entry is
924 * at the head of the list, otherwise only the thread of the previous entry is
925 * modified. The entry pointer is only used to calculate the thread offset,
926 * but is not otherwise used. */
928 afs_int32 RemoveFromList (ut, ea, e, head, ta, t, thread)
929 struct ubik_trans *ut;
930 dbadr ea; /* db addr of head structure */
931 char *e; /* head structure */
932 dbadr *head; /* address of head pointer */
933 dbadr ta; /* db addr of strucure to be removed */
934 char *t; /* structure being removed */
935 dbadr *thread; /* pointer to thread pointer */
937 int threadOffset = ((char *)thread - t);
938 dbadr next_a; /* db addr of next element in list */
939 dbadr loop_a; /* db addr of current list element */
941 if (*head == 0) return -1; /* empty list: not found */
942 next_a = ntohl(*head); /* start at head of list */
943 if (next_a == ta) { /* remove from head of list */
944 code = set_word_addr (ut, ea, e, head, *thread);
949 code = dbread (ut, loop_a+threadOffset, (char *)&next_a, sizeof(dbadr));
950 if (code) return code;
951 if (next_a == 0) return -1; /* end of list: not found */
952 } while (ta != (next_a = ntohl(next_a)));
953 code = dbwrite (ut, loop_a+threadOffset, (char *)thread, sizeof(dbadr));
957 afs_int32 ht_HashOutT (ut, mht, hash, ea, e, old)
958 struct ubik_trans *ut;
959 struct memoryHashTable *mht;
965 struct memoryHTBlock *block;
969 if ((old ? mht->oldLength : mht->length) == 0)
971 code = ht_GetTableBlock (ut, mht, hash, old, &block, &bo);
974 if ((block == 0) || (block->b.bucket[bo] == 0))
977 code = RemoveFromList(ut, block->a, (char *)&block->b,
978 &block->b.bucket[bo], ea, e,
979 (dbadr *)(e+mht->threadOffset));
984 unthread_ea = *(afs_int32 *)((char *)e + mht->threadOffset);
985 if (block->b.bucket[bo] == net_ea) {
986 if (set_word_addr (ut, block->a, &block->b, &block->b.bucket[bo], unthread_ea))
990 loop_a = ntohl(block->b.bucket[bo]);
992 if (dbread (ut, loop_a + mht->threadOffset,
993 (char *)&next_loop_a, sizeof(dbadr)))
995 if (next_loop_a == 0) return -1; /* not found */
996 if (net_ea == next_loop_a) {
997 if (dbwrite (ut, loop_a + mht->threadOffset, (char *)&unthread_ea, sizeof(dbadr)))
1001 loop_a = ntohl (next_loop_a);
1005 if (set_word_addr (ut, 0, &db.h, &mht->ht->entries, htonl(ntohl(mht->ht->entries) - 1)))
1011 ht_HashOut (ut, mht, ea, e)
1012 struct ubik_trans *ut;
1013 struct memoryHashTable *mht;
1021 db_panic ("some ht called with bad mht");
1022 hash = ht_HashEntry (mht, e);
1025 code = ht_HashOutT (ut, mht, hash, ea, e, 1/*old*/);
1032 if (mht->length == 0) /* not found */
1033 ERROR(BUDB_INTERNALERROR);
1034 code = ht_HashOutT (ut, mht, hash, ea, e, 0/*old*/);
1040 code = ht_MoveEntries (ut, mht);
1043 code = ht_MaybeAdjust (ut, mht);
1051 /* generic hash table traversal routines */
1055 scanHashTableBlock(ut, mhtPtr, htBlockPtr, old, length, index,
1056 selectFn, operationFn, rockPtr)
1057 struct ubik_trans *ut;
1058 struct memoryHashTable *mhtPtr;
1059 struct htBlock *htBlockPtr;
1061 afs_int32 length; /* size of whole hash table */
1062 int index; /* base index of this block */
1064 int (*operationFn)();
1067 int type; /* hash table type */
1068 int entrySize; /* hashed entry size */
1070 afs_uint32 *mapEntryPtr = 0; /* for status checks */
1072 char entry[sizeof(struct block)];
1073 dbadr entryAddr, nextEntryAddr;
1078 type = ntohl(mhtPtr->ht->functionType);
1079 entrySize = sizeFunctions[type];
1081 /* step through this hash table block, being careful to stop
1082 * before the end of the overall hash table
1085 for ( i = 0; (i < nHTBuckets) && (index < length); i++, index++ )
1088 nextEntryAddr = ntohl( htBlockPtr->bucket[i] );
1090 /* if this is the old hash table, all entries below the progress mark
1091 * should have been moved to the new hash table
1093 if (old && (index < mhtPtr->progress) && nextEntryAddr)
1094 return BUDB_INTERNALERROR;
1096 /* now walk down the chain of each bucket */
1097 while ( nextEntryAddr )
1100 entryAddr = nextEntryAddr;
1101 if ( dbread(ut, entryAddr, &entry[0], entrySize) )
1102 return(BUDB_INTERNALERROR);
1104 if ( (*selectFn)(entryAddr, &entry[0], rockPtr) )
1106 (*operationFn)(entryAddr, &entry[0], rockPtr);
1109 nextEntryAddr = ntohl( *((dbadr *)(entry + mhtPtr->threadOffset)));
1118 scanHashTable(ut, mhtPtr, selectFn, operationFn, rockPtr)
1119 struct ubik_trans *ut;
1120 struct memoryHashTable *mhtPtr;
1122 int (*operationFn)();
1125 struct htBlock hashTableBlock;
1126 dbadr tableAddr; /* disk addr of hash block */
1127 int tableLength; /* # entries */
1128 int blockLength; /* # blocks */
1130 int blockIndex, entryIndex;
1135 extern int nHTBuckets; /* # buckets in a hash table */
1137 for ( old = 0; old <= 1; old++ )
1141 /* check the old hash table */
1142 tableLength = mhtPtr->oldLength;
1143 if ( tableLength == 0 )
1144 continue; /* nothing to do */
1146 tableAddr = ntohl(mhtPtr->ht->oldTable);
1150 /* check current hash table */
1151 tableLength = mhtPtr->length;
1152 if ( tableLength == 0 )
1153 continue; /* nothing to do */
1155 tableAddr = ntohl(mhtPtr->ht->table);
1158 blockLength = (tableLength-1)/nHTBuckets;
1161 /* follow the hash chain */
1162 for ( i = 0; i <= blockLength; i++ )
1164 /* chain too short */
1165 if ( tableAddr == 0 )
1166 ERROR(BUDB_DATABASEINCONSISTENT);
1168 code = dbread(ut, tableAddr, &hashTableBlock,
1169 sizeof(hashTableBlock));
1173 code = scanHashTableBlock(ut, mhtPtr, &hashTableBlock, old,
1174 tableLength, hashIndex,
1175 selectFn, operationFn,
1180 hashIndex += nHTBuckets;
1181 tableAddr = ntohl(hashTableBlock.h.next);