/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
*/
/*
*/
/*
*
* MODULE: dapl_hash.c
*
* PURPOSE: Hash Table
* Description:
*
* Provides a generic hash table with chaining.
*
* $Id: dapl_hash.c,v 1.10 2003/07/11 18:42:17 hobie16 Exp $
*/
#include "dapl_hash.h"
/*
*
* Structures
*
*/
/*
* A hash table element
*/
typedef struct DAPL_HASH_ELEM
{
void *datum;
/*
* The hash table
*/
struct dapl_hash_table
{
unsigned long num_entries;
unsigned long tbl_size;
unsigned long iterator_bucket;
/*
* statistics - we tally on insert operations, counting
* the number of entries in the whole hash table, as
* well as the length of chains we walk to insert. This
* ignores empty buckets, giving us data on overall table
* the buckets used. If our hash function results in
* hot buckets, this will show it.
*/
};
/*
*
* Defines
*
*/
/* The hash function */
/* datum value in empty table slots (use 0UL or ~0UL as appropriate) */
/* Lookup macro (which falls back to function to rehash) */
{ \
DAPL_HASH_ELEM *element = \
(bucket_head) = (void *)0; \
(bucket_head) = (void *)element; \
} else if (element->next_element) { \
(in_key), \
(void **)&(out_datum), \
(DAPL_HASH_ELEM **)&(bucket_head)); \
} else { \
(bucket_head) = (void *)0; \
}\
}
/*
*
* Internal Functions
*
*/
/*
* Rehash the key (used by add and lookup functions)
*
* Inputs: element element to rehash key
* key, datum datum for key head
* head head for list
*/
static void
void **datum,
DAPL_HASH_ELEM ** head)
{
/*
* assume we looked at the contents of element already,
* and start with the next element.
*/
/*CONSTCOND*/
while (1) {
if (!element) {
break;
}
return;
}
}
*head = 0;
}
/*
* Add a new key to the hash table
*
* Inputs:
* table, key and datum to be added
* allow_dup - DAT_TRUE if dups are allowed
* Outputs:
* report_dup - should you care to know
* Returns:
* DAT_TRUE on success
*/
static DAT_BOOLEAN
void *datum,
{
void *olddatum;
unsigned int chain_len = 0;
if (report_dup) {
(*report_dup) = DAT_FALSE;
}
/*
* Reserved value used for datum
*/
"dapli_hash_add () called with magic NO_DATA value "
"(%p) used as datum!\n", datum);
return (DAT_FALSE);
}
if (found) {
/*
* key exists already
*/
if (report_dup) {
*report_dup = DAT_TRUE;
}
if (!allow_dup) {
"dapli_hash_add () called with duplicate key "
return (DAT_FALSE);
}
}
/*
* Empty head - just fill it in
*/
p_table->num_entries++;
} else {
dapl_os_alloc(sizeof (DAPL_HASH_ELEM));
/*
* Add an element to the end of the chain
*/
if (newelement) {
newelement->next_element = 0;
/* Walk to the end of the chain */
chain_len++;
}
p_table->num_entries++;
} else {
/* allocation failed - should not happen */
}
}
/*
* Tally up our counters. chain_len is one less than current chain
* length.
*/
chain_len++;
}
}
return (status);
}
/*
* Remove element from hash bucket
*
* Inputs:
* element, key to be deleted
* Returns:
* DAT_TRUE on success
*/
static DAT_BOOLEAN
{
lastelement = NULL;
if (p_datum) {
}
if (lastelement) {
/*
* curelement was malloc'd; free it
*/
dapl_os_free((void *) curelement,
sizeof (DAPL_HASH_ELEM));
} else {
/*
* curelement is static list head
*/
if (n) {
/*
* If there is a next element, copy its
* contents into the head and free the
* original next element.
*/
n->next_element;
dapl_os_free((void *) n,
sizeof (DAPL_HASH_ELEM));
} else {
}
}
break;
}
}
}
/*
*
* External Functions
*
*/
/*
* Create a new hash table with at least 'table_size' hash buckets.
*/
{
DAT_COUNT i;
/* Allocate hash table */
goto bail;
}
/* Init hash table, allocate and init and buckets */
goto bail;
}
/* Init the lock anyways */
for (i = 0; i < table_size; i++) {
}
bail:
return (dat_status);
}
/*
* Destroy a hash table
*/
{
return (DAT_SUCCESS);
}
/*
* Returns the number of elements stored in the table
*/
{
return (DAT_SUCCESS);
}
/*
* Inserts the specified data into the table with the given key.
* Duplicates are not expected, and return in error, having done nothing.
*/
{
if (p_table->locking_required) {
}
}
if (p_table->locking_required) {
}
return (dat_status);
}
/*
* Searches for the given key. If found,
* DAT_SUCCESS is returned and the associated
* data is returned in the DAPL_HASH_DATA
* pointer if that pointer is not NULL.
*/
{
void *olddatum;
if (p_table->locking_required) {
} else {
}
if (found) {
if (p_data) {
}
}
return (dat_status);
}
{
if (p_table->num_entries == 0) {
"dapls_hash_remove () called on empty hash table!\n");
return (dat_status);
}
if (p_table->locking_required) {
}
p_table->num_entries--;
}
if (p_table->locking_required) {
}
return (dat_status);
}
/*
* Iterates through the entire hash table return one element at a time.
* Note: this is not a threadsafe routine and hence consumers that
* rely on the hash-tables internal locking are not allowed to use this.
*/
{
/*
* sorry iterate is supported only for consumers that do their
* own locking
*/
if (p_table->locking_required) {
return (DAT_ERROR(DAT_INVALID_PARAMETER, 0));
}
if (op == DAPL_HASH_ITERATE_INIT) {
/* the hash table is empty */
if (p_table->num_entries == 0) {
return (DAT_SUCCESS);
}
/* find the first bucket with valid data */
p_table->iterator_bucket = 0;
/* empty bucket - move on */
} else {
break;
}
}
/* should not be empty if num_entries is non-zero */
} else {
}
} else {
}
/* iterator points to the element to be returned */
/* nothing more left in the hashtable */
return (DAT_SUCCESS);
}
"dapls_hash_iterate: entry found=(%p), bucket(%d)\n",
/* re-position iterator to point to the next valid element */
} else {
/*
* We are here means we've hit the end of the current bucket,
* so start searching for next bucket with a valid entry -
* we only need to look at the head of the bucket
*/
} else {
break;
}
}
}
return (DAT_SUCCESS);
}