hkey_t hash_table_find(const HashTable *const ht, const BinaryKmer key) { const BinaryKmer *ptr; size_t i; uint_fast32_t h; #ifdef HASH_PREFETCH uint_fast32_t h2 = binary_kmer_hash(key,ht->seed+0) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); #endif for(i = 0; i < REHASH_LIMIT; i++) { #ifdef HASH_PREFETCH h = h2; if(ht->buckets[h][HT_BSIZE] == ht->bucket_size) { h2 = binary_kmer_hash(key,ht->seed+i+1) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); } #else h = binary_kmer_hash(key,ht->seed+i) & ht->hash_mask; #endif ptr = hash_table_find_in_bucket_mt(ht, h, key); if(ptr != NULL) return (hkey_t)(ptr - ht->table); if(ht->buckets[h][HT_BSIZE] < ht->bucket_size) return HASH_NOT_FOUND; } rehash_error_exit(ht); }
hkey_t hash_table_find_or_insert_mt(HashTable *ht, const BinaryKmer key, bool *found, volatile uint8_t *bktlocks) { const BinaryKmer *ptr; size_t i; uint_fast32_t h; for(i = 0; i < REHASH_LIMIT; i++) { h = binary_kmer_hash(key,ht->seed+i) & ht->hash_mask; bitlock_yield_acquire(bktlocks, h); ptr = hash_table_find_in_bucket(ht, h, key); if(ptr != NULL) { *found = true; bitlock_release(bktlocks, h); return (hkey_t)(ptr - ht->table); } else if(hash_table_bitems(ht, h) < ht->bucket_size) { *found = false; ptr = hash_table_insert_in_bucket(ht, h, key); __sync_add_and_fetch((volatile uint64_t*)&ht->collisions[i], 1); __sync_add_and_fetch((volatile uint64_t*)&ht->num_kmers, 1); bitlock_release(bktlocks, h); return (hkey_t)(ptr - ht->table); } bitlock_release(bktlocks, h); } rehash_error_exit(ht); }
hkey_t hash_table_find_or_insert_mt(HashTable *ht, const BinaryKmer key, bool *found, volatile uint8_t *bktlocks) { const BinaryKmer *ptr; size_t i; uint_fast32_t h; #ifdef HASH_PREFETCH uint_fast32_t h2 = binary_kmer_hash(key,ht->seed+0) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); #endif for(i = 0; i < REHASH_LIMIT; i++) { #ifdef HASH_PREFETCH h = h2; if(ht->buckets[h][HT_BSIZE] == ht->bucket_size) { h2 = binary_kmer_hash(key,ht->seed+i+1) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); } #else h = binary_kmer_hash(key,ht->seed+i) & ht->hash_mask; #endif bitlock_yield_acquire(bktlocks, h); // We have the bucket lock so noone else can find or insert elements // therefore we can use non-threadsafe bucket functions // bitlock_acquire/release provide memory barriers ptr = hash_table_find_in_bucket_mt(ht, h, key); if(ptr != NULL) { *found = true; bitlock_release(bktlocks, h); return (hkey_t)(ptr - ht->table); } else if(ht->buckets[h][HT_BITEMS] < ht->bucket_size) { *found = false; ptr = hash_table_insert_in_bucket(ht, h, key); bitlock_release(bktlocks, h); __sync_add_and_fetch((volatile uint64_t*)&ht->collisions[i], 1); __sync_add_and_fetch((volatile uint64_t*)&ht->num_kmers, 1); return (hkey_t)(ptr - ht->table); } else { bitlock_release(bktlocks, h); } } rehash_error_exit(ht); }
// This methods inserts an element in the next available bucket // It doesn't check whether another element with the same key is present in the // table used for fast loading when it is known that all the elements in the // input have different key hkey_t hash_table_insert(HashTable *const ht, const BinaryKmer key) { const BinaryKmer *ptr; size_t i; uint_fast32_t h; // prefetch doesn't make sense when not searching.. for(i = 0; i < REHASH_LIMIT; i++) { h = binary_kmer_hash(key,ht->seed+i) & ht->hash_mask; if(ht->buckets[h][HT_BITEMS] < ht->bucket_size) { ptr = hash_table_insert_in_bucket(ht, h, key); ht->collisions[i]++; // only increment collisions when inserting ht->num_kmers++; return (hkey_t)(ptr - ht->table); } } rehash_error_exit(ht); }
hkey_t hash_table_find_or_insert(HashTable *ht, const BinaryKmer key, bool *found) { const BinaryKmer *ptr; size_t i; uint_fast32_t h; #ifdef HASH_PREFETCH uint_fast32_t h2 = binary_kmer_hash(key,ht->seed+0) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); #endif for(i = 0; i < REHASH_LIMIT; i++) { #ifdef HASH_PREFETCH h = h2; if(ht->buckets[h][HT_BSIZE] == ht->bucket_size) { h2 = binary_kmer_hash(key,ht->seed+i+1) & ht->hash_mask; __builtin_prefetch(ht_bckt_ptr(ht, h2), 0, 1); } #else h = binary_kmer_hash(key,ht->seed+i) & ht->hash_mask; #endif ptr = hash_table_find_in_bucket_mt(ht, h, key); if(ptr != NULL) { *found = true; return (hkey_t)(ptr - ht->table); } else if(ht->buckets[h][HT_BITEMS] < ht->bucket_size) { *found = false; ptr = hash_table_insert_in_bucket(ht, h, key); ht->collisions[i]++; // only increment collisions when inserting ht->num_kmers++; return (hkey_t)(ptr - ht->table); } } rehash_error_exit(ht); }