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; }
/** * Init handle mapping module. * Reloads the content of the mapping files it they exist, * else it creates them. * \return 0 if OK, a posix error code else. */ int HandleMap_Init(const handle_map_param_t *p_param) { int rc; /* first check database count */ rc = handlemap_db_count(p_param->databases_directory); if ((rc > 0) && (rc != p_param->database_count)) { LogCrit(COMPONENT_FSAL, "ERROR: The number of existing databases (%u) does not match the requested DB thread count (%u)", rc, p_param->database_count); return HANDLEMAP_INVALID_PARAM; } else if (rc < 0) return -rc; /* init database module */ rc = handlemap_db_init(p_param->databases_directory, p_param->temp_directory, p_param->database_count, p_param->synchronous_insert); if (rc) { LogCrit(COMPONENT_FSAL, "ERROR %d initializing database access", rc); return rc; } /* initialize memory pool of digests and handles */ digest_pool = pool_basic_init("digest_pool", sizeof(digest_pool_entry_t)); handle_pool = pool_basic_init("handle_pool", sizeof(handle_pool_entry_t)); /* create hash table */ handle_hash_config.index_size = p_param->hashtable_size; handle_map_hash = hashtable_init(&handle_hash_config); if (!handle_map_hash) { LogCrit(COMPONENT_FSAL, "ERROR creating hash table for handle mapping"); return HANDLEMAP_INTERNAL_ERROR; } /* reload previous data */ rc = handlemap_db_reaload_all(handle_map_hash); if (rc) { LogCrit(COMPONENT_FSAL, "ERROR %d reloading handle mapping from database", rc); return rc; } return HANDLEMAP_SUCCESS; }