6 typedef struct stat64 VAL;
16 unsigned int // boolean
17 EQUAL(PKEY key1, PKEY key2){
18 return *key1 == *key2;
22 #define MIN(x,y) (((x)<(y))?(x):(y))
26 #define MAX(x,y) (((x)>(y))?(x):(y))
30 ////////////////////////////////////////////////////////////////////////////
31 ////////////////////////////////////////////////////////////////////////////
32 // hash table support for efficient lookup of duplicate inodes */
33 ////////////////////////////////////////////////////////////////////////////
34 ////////////////////////////////////////////////////////////////////////////
36 #define Multiplier (0x9e3779b9)
37 #define MaxLogBuckets (((sizeof (unsigned long))*8) - 2)
38 #define MaxBuckets (1<<MaxLogBuckets)
39 #define MinLogBuckets (4)
40 #define MinBuckets (1<<MinLogBuckets)
42 // Thresholds for rehashing the table: *)
43 // to avoid crazy oscillations, we must have MaxDensity > 2*MinDensity; *)
44 // to avoid excessive probes, we must try to keep MaxDensity low. *)
45 // Divide by 100 before using
46 #define MaxDensity 75 /* max numEntries/NUMBER(buckets) */
47 #define MinDensity 20 /* min numEntries/NUMBER(buckets) */
48 #define IdealDensity 50
49 #define BITSIZE(x) (sizeof(x)*8)
51 #define NEW(type,num) ((type*)malloc(sizeof(type)*num))
52 #define DISPOSE(ptr) (free((void*)ptr))
54 ////////////////////////////////////////////////////////////////////////////
55 ////////////////////////////////////////////////////////////////////////////
56 // Generic Hash Entry Type
57 ////////////////////////////////////////////////////////////////////////////
58 ////////////////////////////////////////////////////////////////////////////
60 typedef struct VoidList {
61 struct VoidList *tail;
62 } VoidList, *PVoidList;
64 typedef struct HashTable {
66 unsigned int numBuckets; // number of buckets
67 unsigned int minLogBuckets; // minimum value for Log_2(initial size)
68 unsigned int logBuckets; // CEILING(Log2(NUMBER(buckets^)))
69 unsigned int maxEntries; // maximum number of entries
70 unsigned int minEntries; // minimum number of entries
71 unsigned int numEntries; // current num of entries in table
72 PVoidList cache; // cache of removed elements
73 int cacheSize; // current size of the cache
74 int maxCacheSize; // maximum size, -1 means unbounded, 0 no cache
75 } HashTable, *PHashTable;
77 ////////////////////////////////////////////////////////////////////////////
78 ////////////////////////////////////////////////////////////////////////////
80 ////////////////////////////////////////////////////////////////////////////
81 ////////////////////////////////////////////////////////////////////////////
84 Init(PHashTable tbl, unsigned int n, int maxCacheSize);
87 Dispose(PHashTable tbl);
90 Log_2(unsigned int x);
93 NewBuckets(PHashTable tbl, unsigned int logBuckets);
96 // Generic Hash Table support
100 Init(PHashTable tbl, unsigned int n, int maxCacheSize){
104 idealBuckets = MIN(((n*100)/IdealDensity),MaxBuckets);
105 minBuckets = MAX(MinBuckets, idealBuckets);
106 tbl->minLogBuckets = Log_2(minBuckets);
108 NewBuckets(tbl, tbl->minLogBuckets);
110 tbl->maxCacheSize = maxCacheSize;
118 // Internal procedures
122 Log_2(unsigned int x){
123 // return CEILING(LOG_2(x))
124 unsigned int log = 0;
128 while ((log < MaxLogBuckets) && (x > n)){
136 NewBuckets(PHashTable tbl, unsigned int logBuckets){
137 // Allocate "2^logBuckets" buckets.
138 unsigned int numBuckets = 1 << logBuckets;
142 tbl->buckets = NEW(PVoidList, numBuckets);
143 tbl->numBuckets = numBuckets;
146 for (i=0; i<tbl->numBuckets; i++){
149 tbl->logBuckets = logBuckets;
150 tbl->maxEntries = MaxDensity * numBuckets / 100;
151 tbl->minEntries = MinDensity * numBuckets / 100;
155 #define NULL (void*)0
166 ////////////////////////////////////////////////////////////////////////////
167 ////////////////////////////////////////////////////////////////////////////
168 // Type specific hash entry
169 ////////////////////////////////////////////////////////////////////////////
170 ////////////////////////////////////////////////////////////////////////////
171 typedef struct EntryList {
172 struct EntryList *tail;
175 }EntryList, *PEntryList;
177 ////////////////////////////////////////////////////////////////////////////
178 ////////////////////////////////////////////////////////////////////////////
179 // Type specific Hash implementation functions
180 ////////////////////////////////////////////////////////////////////////////
181 ////////////////////////////////////////////////////////////////////////////
185 Rehash(PHashTable tbl, unsigned int logBuckets) {
186 // Reallocate "2^logBuckets" buckets, and rehash the entries into
189 PVoidList *oldBucketPointer;
191 PEntryList *nb, *nbh;
192 PEntryList that, tail;
195 unsigned int oldNumBuckets;
198 assert(logBuckets <= MaxLogBuckets);
199 assert(logBuckets >= tbl->minLogBuckets);
200 oldBucketPointer = tbl->buckets;
201 ob = (PEntryList*)tbl->buckets;
202 oldNumBuckets = tbl->numBuckets;
204 NewBuckets(tbl, logBuckets);
205 nb = (PEntryList*)tbl->buckets;
207 for(i=0;i<oldNumBuckets;i++){
210 while (that != NULL) {
211 index = (HASH(&(that->key))*Multiplier)>>(BITSIZE(unsigned long)-tbl->logBuckets);
219 DISPOSE (oldBucketPointer);
223 unsigned int // boolean
224 Get(PHashTable tbl, PKEY key, PVAL *val){
228 index = (HASH(key)*Multiplier)>>(BITSIZE(unsigned long)-tbl->logBuckets);
229 that = (PEntryList)tbl->buckets[index];
230 while ((that != NULL) && !EQUAL(key,&(that->key))) {
243 unsigned int // boolean
244 Put(PHashTable tbl, PKEY key, PVAL *val){
250 index = (HASH(key)*Multiplier)>>(BITSIZE(unsigned long)-tbl->logBuckets);
251 first = (PEntryList*)&(tbl->buckets[index]);
253 while ((that != NULL) && !EQUAL(key, &(that->key))){
257 // found an entry in the hash table given above key
262 // check if we can reuse something from the cache
263 if (tbl->cache != NULL) {
264 that = (PEntryList)tbl->cache;
265 tbl->cache = (PVoidList)tbl->cache->tail;
271 that = NEW(EntryList,1);
279 if ((tbl->logBuckets < MaxLogBuckets)
280 && (tbl->numEntries > tbl->maxEntries)){
281 Rehash(tbl, tbl->logBuckets + 1); // too crowded
292 Delete(PHashTable tbl,PKEY key){
293 PEntryList that, prev;
297 index = (HASH(key)*Multiplier)>>(BITSIZE(unsigned long)-tbl->logBuckets);
298 first = (PEntryList*)&(tbl->buckets[index]);
302 while ((that != NULL) && !EQUAL(key, &(that->key))){
311 prev->tail = that->tail;
313 if ((tbl->maxCacheSize == -1)||(tbl->cacheSize < tbl->maxCacheSize)) {
314 that->tail = (PEntryList)tbl->cache;
315 tbl->cache = (PVoidList)that;
322 if (tbl->maxCacheSize == 0) {
323 if ((tbl->logBuckets > tbl->minLogBuckets)
324 && (tbl->numEntries < tbl->minEntries)) {
325 Rehash(tbl, tbl->logBuckets - 1); // too sparse
335 typedef void (*callback)(PKEY key, PVAL val);
338 Iterate(PHashTable tbl, callback fn)
343 for(i=0;i<tbl->numBuckets;i++) {
344 that = tbl->buckets[i];
345 while ( that != (PVoidList)0 ) {
346 PEntryList entry = (PEntryList)that;
347 fn(&entry->key,&entry->val);
354 Dispose(PHashTable tbl)
356 PVoidList that, next;
359 for(i=0;i<tbl->numBuckets;i++) {
360 that = tbl->buckets[i];
361 while( that != NULL) {
368 DISPOSE(tbl->buckets);
369 assert(tbl->numEntries = 0);