struct hash_table * hashtable_init(struct hash_param *hparam) { /* The hash table being constructed */ struct hash_table *ht = NULL; /* The index for initializing each partition */ uint32_t index = 0; /* Read-Write Lock attributes, to prevent write starvation under GLIBC */ pthread_rwlockattr_t rwlockattr; /* Hash partition */ struct hash_partition *partition = NULL; /* The number of fully initialized partitions */ uint32_t completed = 0; if (pthread_rwlockattr_init(&rwlockattr) != 0) return NULL; /* At some point factor this out into the OS directory. it is necessary to prevent writer starvation under GLIBC. */ #ifdef GLIBC if ((pthread_rwlockattr_setkind_np (&rwlockattrs, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP)) != 0) { LogCrit(COMPONENT_HASHTABLE, "Unable to set writer-preference on lock attribute."); goto deconstruct; } #endif /* GLIBC */ ht = gsh_calloc(1, sizeof(struct hash_table) + (sizeof(struct hash_partition) * hparam->index_size)); /* Fixup entry size */ if (hparam->flags & HT_FLAG_CACHE) { if (!hparam->cache_entry_count) /* works fine with a good hash algo */ hparam->cache_entry_count = 32767; } /* We need to save copy of the parameters in the table. */ ht->parameter = *hparam; for (index = 0; index < hparam->index_size; ++index) { partition = (&ht->partitions[index]); RBT_HEAD_INIT(&(partition->rbt)); if (pthread_rwlock_init(&partition->lock, &rwlockattr) != 0) { LogCrit(COMPONENT_HASHTABLE, "Unable to initialize lock in hash table."); goto deconstruct; } /* Allocate a cache if requested */ if (hparam->flags & HT_FLAG_CACHE) partition->cache = gsh_calloc(1, cache_page_size(ht)); completed++; } ht->node_pool = pool_basic_init(NULL, sizeof(rbt_node_t)); ht->data_pool = pool_basic_init(NULL, sizeof(struct hash_data)); pthread_rwlockattr_destroy(&rwlockattr); return ht; deconstruct: while (completed != 0) { if (hparam->flags & HT_FLAG_CACHE) gsh_free(ht->partitions[completed - 1].cache); PTHREAD_RWLOCK_destroy(&(ht->partitions[completed - 1].lock)); completed--; } if (ht->node_pool) pool_destroy(ht->node_pool); if (ht->data_pool) pool_destroy(ht->data_pool); gsh_free(ht); return ht = NULL; }
hash_table_t *HashTable_Init(hash_parameter_t hparam) { hash_table_t *ht; unsigned int i = 0; pthread_mutexattr_t mutexattr; /* Sanity check */ if((ht = (hash_table_t *) Mem_Alloc(sizeof(hash_table_t))) == NULL) return NULL; /* we have to keep the discriminant values */ ht->parameter = hparam; if(pthread_mutexattr_init(&mutexattr) != 0) return NULL; /* Initialization of the node array */ if((ht->array_rbt = (struct rbt_head *)Mem_Alloc(sizeof(struct rbt_head) * hparam.index_size)) == NULL) return NULL; /* Initialization of the stat array */ if((ht->stat_dynamic = (hash_stat_dynamic_t *) Mem_Alloc(sizeof(hash_stat_dynamic_t) * hparam.index_size)) == NULL) return NULL; /* Init the stats */ memset((char *)ht->stat_dynamic, 0, sizeof(hash_stat_dynamic_t) * hparam.index_size); /* Initialization of the semaphores array */ if((ht->array_lock = (rw_lock_t *) Mem_Alloc(sizeof(rw_lock_t) * hparam.index_size)) == NULL) return NULL; /* Initialize the array of pre-allocated node */ if((ht->node_prealloc = (struct rbt_node **)Mem_Alloc(sizeof(struct rbt_node *) * hparam.index_size)) == NULL) return NULL; if((ht->pdata_prealloc = (hash_data_t **) Mem_Alloc(sizeof(hash_data_t *) * hparam.index_size)) == NULL) return NULL; for(i = 0; i < hparam.index_size; i++) { #ifndef _NO_BLOCK_PREALLOC if((ht->node_prealloc[i] = PreAllocNode(hparam.nb_node_prealloc)) == NULL) return NULL; if((ht->pdata_prealloc[i] = PreAllocPdata(hparam.nb_node_prealloc)) == NULL) return NULL; #else ht->node_prealloc[i] = PreAllocNode(hparam.nb_node_prealloc); ht->pdata_prealloc[i] = PreAllocPdata(hparam.nb_node_prealloc); #endif } /* Initialize each of the RB-Tree, mutexes and stats */ for(i = 0; i < hparam.index_size; i++) { /* RBT Init */ RBT_HEAD_INIT(&(ht->array_rbt[i])); /* Mutex Init */ if(rw_lock_init(&(ht->array_lock[i])) != 0) return NULL; /* Initialization of the stats structure */ ht->stat_dynamic[i].nb_entries = 0; ht->stat_dynamic[i].ok.nb_set = 0; ht->stat_dynamic[i].ok.nb_get = 0; ht->stat_dynamic[i].ok.nb_del = 0; ht->stat_dynamic[i].ok.nb_test = 0; ht->stat_dynamic[i].err.nb_set = 0; ht->stat_dynamic[i].err.nb_get = 0; ht->stat_dynamic[i].err.nb_del = 0; ht->stat_dynamic[i].err.nb_test = 0; ht->stat_dynamic[i].notfound.nb_set = 0; ht->stat_dynamic[i].notfound.nb_get = 0; ht->stat_dynamic[i].notfound.nb_del = 0; ht->stat_dynamic[i].notfound.nb_test = 0; } /* final return, if we arrive here, then everything is alright */ return ht; } /* HashTable_Init */