/** * @brief Initialise the hashtable. * * Allocate the hash table entries and initialise the hash masks. * * @param hash_table Hash table to setup. * @param size Requested size for the hash table in number of entries. */ void hash_init(HashTable *hash_table, const unsigned long long size) { int i, n_way; for (n_way = 1; n_way < HASH_N_WAY; n_way <<= 1); assert(hash_table != NULL); assert((n_way & -n_way) == n_way); info("< init hashtable of %llu entries>\n", size); if (hash_table->hash != NULL) free(hash_table->memory); hash_table->memory = malloc((size + n_way + 1) * sizeof (Hash)); if (hash_table->memory == NULL) { fatal_error("hash_init: cannot allocate the hash table\n"); } if (HASH_ALIGNED) { const size_t alignment = n_way * sizeof (Hash) - 1; hash_table->hash = (Hash*) (((size_t) hash_table->memory + alignment) & ~alignment); hash_table->hash_mask = size - n_way; } else { hash_table->hash = (Hash*) hash_table->memory; hash_table->hash_mask = size - 1; } hash_cleanup(hash_table); hash_table->n_lock = 256 * MAX(get_cpu_number(), 1); hash_table->lock_mask = hash_table->n_lock - 1; hash_table->n_lock += n_way + 1; hash_table->lock = (HashLock*) malloc(hash_table->n_lock * sizeof (HashLock)); for (i = 0; i < hash_table->n_lock; ++i) spin_init(hash_table->lock + i); }
EC_API void ec_hash_destroy( ec_hash table ) { ENTERF; if (table) { hash_cleanup( table ); hash_free( table ); } }
/* bul_cleanup - cleans up global bul */ void bul_cleanup(void) { hash_cleanup(&bul_hash); }
/* bul_home_cleanup - cleans up a bul * @bul: binding update list to clean up */ void bul_home_cleanup(struct hash *bul) { hash_iterate(bul, bule_cleanup, bul); hash_cleanup(bul); }
void bcache_cleanup(void) { pthread_rwlock_wrlock(&bc_lock); hash_cleanup(&bc_hash); pthread_rwlock_unlock(&bc_lock); }
static EcBool hash_expand( ec_hash table ) { EcUInt newCapacity = 0, newPrimeIndex; EcUInt i; ec_hash new_table = NULL; ec_hash_entry entry; EcAny invkey; EcAny invval; ENTERF; #ifdef EC_DEBUG if (debTable) { EcUInt lf; if (H_CAPACITY(table)) { lf = (H_ENTRIES(table) << SHIFTAMOUNT); lf /= H_CAPACITY(table); } else lf = 0; #if EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "**************** hash_expand ******************" ); VADEBMESSAGE( debTable, "Current load factor: %ld [LO %ld, HI %ld]", (long)lf, (long)H_LOLOAD(table), (long)H_HILOAD(table) ); #endif } #endif ASSERT( table ); ASSERT( !new_table ); ASSERT( table != new_table ); #if CHECK_PRIME ASSERT( (H_CAPACITY(table) == 0) || isprime(H_CAPACITY(table)) ); #endif invkey = H_INVKEY(table); invval = H_INVVAL(table); if (H_PRIMEINDEX(table) == 0) { newPrimeIndex = FIRSTPRIME; ASSERT(newPrimeIndex < nprimes); newCapacity = primes[newPrimeIndex]; #if CHECK_PRIME ASSERT( isprime( newCapacity ) ); #endif for (i = 1; i < nprimes; i++) { if (primes[i] >= H_MINSIZE(table)) { newPrimeIndex = i; newCapacity = primes[i]; H_MINSIZE(table) = primes[i]; break; } } ASSERT(newCapacity >= H_MINSIZE(table)); ASSERT(H_MINSIZE(table) > 2); #if CHECK_PRIME ASSERT( isprime( newCapacity ) ); #endif #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "*1*" ); #endif } else { EcUInt curLoad; newPrimeIndex = H_PRIMEINDEX(table); if (H_CAPACITY(table)) { curLoad = H_ENTRIES(table) << SHIFTAMOUNT; curLoad /= H_CAPACITY(table); } else curLoad = H_HILOAD(table) + 1; /* capacity null => expand ! */ if (curLoad >= H_HILOAD(table)) { do { newPrimeIndex++; ASSERT(newPrimeIndex < nprimes); newCapacity = primes[newPrimeIndex]; ASSERT(newCapacity); #if CHECK_PRIME ASSERT( isprime( newCapacity ) ); #endif curLoad = H_ENTRIES(table) << SHIFTAMOUNT; curLoad /= newCapacity; } while (curLoad > H_LOLOAD(table)); } #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "*2*" ); #endif } ASSERT(newCapacity >= H_MINSIZE(table)); #if CHECK_PRIME ASSERT( isprime( newCapacity ) ); #endif if (! H_ENTRYBASE(table)) { H_ENTRYBASE(table) = (ec_hash_entry) ec_malloc( sizeof(struct ec_hash_entry_struct) * newCapacity ); if (! H_ENTRYBASE(table)) return FALSE; H_CAPACITY(table) = newCapacity; H_PRIMEINDEX(table) = newPrimeIndex; /* IMPORTANT: initialize new slots */ for (i = 0; i < newCapacity; i++) { EC_HASH_ENTRY_KEY(H_ENTRY(table, i)) = invkey; EC_HASH_ENTRY_VALUE(H_ENTRY(table, i)) = invval; } #if CHECK_PRIME ASSERT( isprime(H_CAPACITY(table)) ); #endif return TRUE; } else { EcBool old_xfer; #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "Expanding table to %ld elements", (long)newCapacity ); #endif ASSERT( !new_table ); new_table = hash_alloc(); ASSERT( !H_ENTRYBASE(new_table) ); H_DEF(new_table) = H_DEF(table); H_ENTRIES(new_table) = 0; H_CAPACITY(new_table) = 0; H_PRIMEINDEX(new_table) = 0; H_ENTRYBASE(new_table) = 0; /* new_table.loLoad = (1 << SHIFTAMOUNT); */ /* BUG CORRECTED */ /* new_table.hiLoad = (1 << SHIFTAMOUNT); */ H_MINSIZE(new_table) = H_MINSIZE(table); H_LOLOAD(new_table) = H_LOLOAD(table); H_HILOAD(new_table) = H_HILOAD(table); H_ENTRYBASE(new_table) = (ec_hash_entry) ec_malloc( sizeof(struct ec_hash_entry_struct) * newCapacity ); if (! H_ENTRYBASE(new_table)) return FALSE; H_ENTRIES(new_table) = 0; H_CAPACITY(new_table) = newCapacity; H_PRIMEINDEX(new_table) = newPrimeIndex; #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "newCapacity: %ld, newPrimeIndex: %ld", (long)newCapacity, (long)newPrimeIndex ); #endif /* IMPORTANT: initialize new slots */ for (i = 0; i < newCapacity; i++) { EC_HASH_ENTRY_KEY(H_ENTRY(new_table, i)) = invkey; EC_HASH_ENTRY_VALUE(H_ENTRY(new_table, i)) = invval; } #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "oldTable capacity: %ld entries: %ld\n", (long)H_CAPACITY(table), (long)H_ENTRIES(table) ); #endif /* fill new table with old values */ ASSERT( table != new_table ); old_xfer = xfer_only; xfer_only = TRUE; for (i = 0; i < H_CAPACITY(table); i++) { entry = H_ENTRY(table, i); if (EC_HASH_ENTRY_KEY(entry) != invkey) { ec_hash_set( new_table, EC_HASH_ENTRY_KEY(entry), EC_HASH_ENTRY_VALUE(entry) ); } } xfer_only = old_xfer; #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "newTable capacity: %ld entries: %ld\n", (long)H_CAPACITY(new_table), (long)H_ENTRIES(new_table) ); #endif ASSERT( H_ENTRIES(table) == H_ENTRIES(new_table) ); /* free old table contents */ hash_cleanup( table ); /* move new table to old one */ memcpy( table, new_table, sizeof(struct ec_hash_struct) ); /* free new table space (not contents !) */ hash_free( new_table ); new_table = NULL; #if EC_DEBUG && EC_HAS_VARARGS_MACRO VADEBMESSAGE( debTable, "Table capacity: %ld entries: %ld\n", (long)H_CAPACITY(table), (long)H_ENTRIES(table) ); #endif #if CHECK_PRIME ASSERT( isprime(H_CAPACITY(table)) ); #endif return TRUE; } return FALSE; }