xref: /onnv-gate/usr/src/lib/udapl/udapl_tavor/common/dapl_hash.c (revision 9517:b4839b0aa7a4)
1*9517SBill.Taylor@Sun.COM /*
2*9517SBill.Taylor@Sun.COM  * CDDL HEADER START
3*9517SBill.Taylor@Sun.COM  *
4*9517SBill.Taylor@Sun.COM  * The contents of this file are subject to the terms of the
5*9517SBill.Taylor@Sun.COM  * Common Development and Distribution License (the "License").
6*9517SBill.Taylor@Sun.COM  * You may not use this file except in compliance with the License.
7*9517SBill.Taylor@Sun.COM  *
8*9517SBill.Taylor@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9517SBill.Taylor@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9517SBill.Taylor@Sun.COM  * See the License for the specific language governing permissions
11*9517SBill.Taylor@Sun.COM  * and limitations under the License.
12*9517SBill.Taylor@Sun.COM  *
13*9517SBill.Taylor@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9517SBill.Taylor@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9517SBill.Taylor@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9517SBill.Taylor@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9517SBill.Taylor@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9517SBill.Taylor@Sun.COM  *
19*9517SBill.Taylor@Sun.COM  * CDDL HEADER END
20*9517SBill.Taylor@Sun.COM  */
21*9517SBill.Taylor@Sun.COM 
22*9517SBill.Taylor@Sun.COM /*
23*9517SBill.Taylor@Sun.COM  * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24*9517SBill.Taylor@Sun.COM  */
25*9517SBill.Taylor@Sun.COM 
26*9517SBill.Taylor@Sun.COM /*
27*9517SBill.Taylor@Sun.COM  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28*9517SBill.Taylor@Sun.COM  * Use is subject to license terms.
29*9517SBill.Taylor@Sun.COM  */
30*9517SBill.Taylor@Sun.COM 
31*9517SBill.Taylor@Sun.COM /*
32*9517SBill.Taylor@Sun.COM  *
33*9517SBill.Taylor@Sun.COM  * MODULE: dapl_hash.c
34*9517SBill.Taylor@Sun.COM  *
35*9517SBill.Taylor@Sun.COM  * PURPOSE: Hash Table
36*9517SBill.Taylor@Sun.COM  * Description:
37*9517SBill.Taylor@Sun.COM  *
38*9517SBill.Taylor@Sun.COM  * Provides a generic hash table with chaining.
39*9517SBill.Taylor@Sun.COM  *
40*9517SBill.Taylor@Sun.COM  * $Id: dapl_hash.c,v 1.10 2003/07/11 18:42:17 hobie16 Exp $
41*9517SBill.Taylor@Sun.COM  */
42*9517SBill.Taylor@Sun.COM 
43*9517SBill.Taylor@Sun.COM #include "dapl_hash.h"
44*9517SBill.Taylor@Sun.COM 
45*9517SBill.Taylor@Sun.COM /*
46*9517SBill.Taylor@Sun.COM  *
47*9517SBill.Taylor@Sun.COM  * Structures
48*9517SBill.Taylor@Sun.COM  *
49*9517SBill.Taylor@Sun.COM  */
50*9517SBill.Taylor@Sun.COM 
51*9517SBill.Taylor@Sun.COM /*
52*9517SBill.Taylor@Sun.COM  * A hash table element
53*9517SBill.Taylor@Sun.COM  */
54*9517SBill.Taylor@Sun.COM typedef struct DAPL_HASH_ELEM
55*9517SBill.Taylor@Sun.COM {
56*9517SBill.Taylor@Sun.COM 	struct DAPL_HASH_ELEM	*next_element;
57*9517SBill.Taylor@Sun.COM 	DAPL_HASH_KEY		key;
58*9517SBill.Taylor@Sun.COM 	void			*datum;
59*9517SBill.Taylor@Sun.COM } DAPL_HASH_ELEM;
60*9517SBill.Taylor@Sun.COM 
61*9517SBill.Taylor@Sun.COM /*
62*9517SBill.Taylor@Sun.COM  * The hash table
63*9517SBill.Taylor@Sun.COM  */
64*9517SBill.Taylor@Sun.COM struct dapl_hash_table
65*9517SBill.Taylor@Sun.COM {
66*9517SBill.Taylor@Sun.COM 	unsigned long		num_entries;
67*9517SBill.Taylor@Sun.COM 	unsigned long		tbl_size;
68*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM		*table;
69*9517SBill.Taylor@Sun.COM 	DAT_BOOLEAN		locking_required; /* internal locking reqd */
70*9517SBill.Taylor@Sun.COM 	DAPL_OS_LOCK		lock;
71*9517SBill.Taylor@Sun.COM 	unsigned long		iterator_bucket;
72*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM		*iterator;
73*9517SBill.Taylor@Sun.COM 	/*
74*9517SBill.Taylor@Sun.COM 	 * statistics - we tally on insert operations, counting
75*9517SBill.Taylor@Sun.COM 	 * the number of entries in the whole hash table, as
76*9517SBill.Taylor@Sun.COM 	 * well as the length of chains we walk to insert.  This
77*9517SBill.Taylor@Sun.COM 	 * ignores empty buckets, giving us data on overall table
78*9517SBill.Taylor@Sun.COM 	 * occupancy, as well as max/average chain length for
79*9517SBill.Taylor@Sun.COM 	 * the buckets used.  If our hash function results in
80*9517SBill.Taylor@Sun.COM 	 * hot buckets, this will show it.
81*9517SBill.Taylor@Sun.COM 	 */
82*9517SBill.Taylor@Sun.COM 	uint64_t		hash_tbl_inserts;   /* total inserts ops    */
83*9517SBill.Taylor@Sun.COM 	uint64_t		hash_tbl_max;	/* max in entire table  */
84*9517SBill.Taylor@Sun.COM 	uint64_t		hash_tbl_total;	/* total in table	*/
85*9517SBill.Taylor@Sun.COM 	uint64_t		hash_chn_max;	/* longest chain	*/
86*9517SBill.Taylor@Sun.COM 	uint64_t		hash_chn_total;	/* total non-0 lenghts  */
87*9517SBill.Taylor@Sun.COM };
88*9517SBill.Taylor@Sun.COM 
89*9517SBill.Taylor@Sun.COM 
90*9517SBill.Taylor@Sun.COM /*
91*9517SBill.Taylor@Sun.COM  *
92*9517SBill.Taylor@Sun.COM  * Defines
93*9517SBill.Taylor@Sun.COM  *
94*9517SBill.Taylor@Sun.COM  */
95*9517SBill.Taylor@Sun.COM 
96*9517SBill.Taylor@Sun.COM /* The hash function */
97*9517SBill.Taylor@Sun.COM #define	DAPL_DOHASH(key, hashsize)   ((uint64_t)((key) % (hashsize)))
98*9517SBill.Taylor@Sun.COM 
99*9517SBill.Taylor@Sun.COM /* datum value in empty table slots  (use 0UL or ~0UL as appropriate) */
100*9517SBill.Taylor@Sun.COM #define	NO_DATUM_VALUE		((void *) 0UL)
101*9517SBill.Taylor@Sun.COM #define	NO_DATUM(value)		((value) == NO_DATUM_VALUE)
102*9517SBill.Taylor@Sun.COM 
103*9517SBill.Taylor@Sun.COM /* Lookup macro (which falls back to function to rehash) */
104*9517SBill.Taylor@Sun.COM #define	DAPL_HASHLOOKUP(p_table, in_key, out_datum, bucket_head) \
105*9517SBill.Taylor@Sun.COM 	{ \
106*9517SBill.Taylor@Sun.COM 		DAPL_HASH_ELEM *element = \
107*9517SBill.Taylor@Sun.COM 		&((p_table)->table)[DAPL_DOHASH(in_key, (p_table)->tbl_size)]; \
108*9517SBill.Taylor@Sun.COM 		if (NO_DATUM(element->datum)) { \
109*9517SBill.Taylor@Sun.COM 			(bucket_head) = (void *)0; \
110*9517SBill.Taylor@Sun.COM 		} else if (element->key == (DAPL_HASH_KEY) (in_key)) { \
111*9517SBill.Taylor@Sun.COM 			(out_datum) = element->datum; \
112*9517SBill.Taylor@Sun.COM 			(bucket_head) = (void *)element; \
113*9517SBill.Taylor@Sun.COM 		} else if (element->next_element) { \
114*9517SBill.Taylor@Sun.COM 			dapli_hash_rehash(element, \
115*9517SBill.Taylor@Sun.COM 					(in_key), \
116*9517SBill.Taylor@Sun.COM 					(void **)&(out_datum), \
117*9517SBill.Taylor@Sun.COM 					(DAPL_HASH_ELEM **)&(bucket_head)); \
118*9517SBill.Taylor@Sun.COM 		} else { \
119*9517SBill.Taylor@Sun.COM 			(bucket_head) = (void *)0; \
120*9517SBill.Taylor@Sun.COM 		}\
121*9517SBill.Taylor@Sun.COM 	}
122*9517SBill.Taylor@Sun.COM 
123*9517SBill.Taylor@Sun.COM 
124*9517SBill.Taylor@Sun.COM /*
125*9517SBill.Taylor@Sun.COM  *
126*9517SBill.Taylor@Sun.COM  * Internal Functions
127*9517SBill.Taylor@Sun.COM  *
128*9517SBill.Taylor@Sun.COM  */
129*9517SBill.Taylor@Sun.COM 
130*9517SBill.Taylor@Sun.COM /*
131*9517SBill.Taylor@Sun.COM  * Rehash the key (used by add and lookup functions)
132*9517SBill.Taylor@Sun.COM  *
133*9517SBill.Taylor@Sun.COM  * Inputs:  element	element to rehash key
134*9517SBill.Taylor@Sun.COM  *	    key, datum	datum for key head
135*9517SBill.Taylor@Sun.COM  *	    head	head for list
136*9517SBill.Taylor@Sun.COM  */
137*9517SBill.Taylor@Sun.COM static void
dapli_hash_rehash(DAPL_HASH_ELEM * element,DAPL_HASH_KEY key,void ** datum,DAPL_HASH_ELEM ** head)138*9517SBill.Taylor@Sun.COM dapli_hash_rehash(
139*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM	*element,
140*9517SBill.Taylor@Sun.COM 	DAPL_HASH_KEY	key,
141*9517SBill.Taylor@Sun.COM 	void		**datum,
142*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM	** head)
143*9517SBill.Taylor@Sun.COM {
144*9517SBill.Taylor@Sun.COM 	/*
145*9517SBill.Taylor@Sun.COM 	 * assume we looked at the contents of element already,
146*9517SBill.Taylor@Sun.COM 	 * and start with the next element.
147*9517SBill.Taylor@Sun.COM 	 */
148*9517SBill.Taylor@Sun.COM 	dapl_os_assert(element->next_element);
149*9517SBill.Taylor@Sun.COM 	dapl_os_assert(!NO_DATUM(element->datum));
150*9517SBill.Taylor@Sun.COM 
151*9517SBill.Taylor@Sun.COM 	*head = element;
152*9517SBill.Taylor@Sun.COM 	/*CONSTCOND*/
153*9517SBill.Taylor@Sun.COM 	while (1) {
154*9517SBill.Taylor@Sun.COM 		element = element->next_element;
155*9517SBill.Taylor@Sun.COM 		if (!element) {
156*9517SBill.Taylor@Sun.COM 			break;
157*9517SBill.Taylor@Sun.COM 		}
158*9517SBill.Taylor@Sun.COM 		if (element->key == key) {
159*9517SBill.Taylor@Sun.COM 			*datum = element->datum;
160*9517SBill.Taylor@Sun.COM 			return;
161*9517SBill.Taylor@Sun.COM 		}
162*9517SBill.Taylor@Sun.COM 	}
163*9517SBill.Taylor@Sun.COM 	*head = 0;
164*9517SBill.Taylor@Sun.COM }
165*9517SBill.Taylor@Sun.COM 
166*9517SBill.Taylor@Sun.COM /*
167*9517SBill.Taylor@Sun.COM  * Add a new key to the hash table
168*9517SBill.Taylor@Sun.COM  *
169*9517SBill.Taylor@Sun.COM  * Inputs:
170*9517SBill.Taylor@Sun.COM  *          table, key and datum to be added
171*9517SBill.Taylor@Sun.COM  *          allow_dup   - DAT_TRUE if dups are allowed
172*9517SBill.Taylor@Sun.COM  * Outputs:
173*9517SBill.Taylor@Sun.COM  *          report_dup  - should you care to know
174*9517SBill.Taylor@Sun.COM  * Returns:
175*9517SBill.Taylor@Sun.COM  *          DAT_TRUE on success
176*9517SBill.Taylor@Sun.COM  */
177*9517SBill.Taylor@Sun.COM static DAT_BOOLEAN
dapli_hash_add(DAPL_HASH_TABLEP p_table,DAPL_HASH_KEY key,void * datum,DAT_BOOLEAN allow_dup,DAT_BOOLEAN * report_dup)178*9517SBill.Taylor@Sun.COM dapli_hash_add(
179*9517SBill.Taylor@Sun.COM 	DAPL_HASH_TABLEP	p_table,
180*9517SBill.Taylor@Sun.COM 	DAPL_HASH_KEY		key,
181*9517SBill.Taylor@Sun.COM 	void			*datum,
182*9517SBill.Taylor@Sun.COM 	DAT_BOOLEAN		allow_dup,
183*9517SBill.Taylor@Sun.COM 	DAT_BOOLEAN		*report_dup)
184*9517SBill.Taylor@Sun.COM {
185*9517SBill.Taylor@Sun.COM 	void		*olddatum;
186*9517SBill.Taylor@Sun.COM 	DAPL_HASH_KEY   hashValue;
187*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM *found;
188*9517SBill.Taylor@Sun.COM 	DAT_BOOLEAN	status = DAT_FALSE;
189*9517SBill.Taylor@Sun.COM 	unsigned int    chain_len = 0;
190*9517SBill.Taylor@Sun.COM 
191*9517SBill.Taylor@Sun.COM 	if (report_dup) {
192*9517SBill.Taylor@Sun.COM 		(*report_dup) = DAT_FALSE;
193*9517SBill.Taylor@Sun.COM 	}
194*9517SBill.Taylor@Sun.COM 
195*9517SBill.Taylor@Sun.COM 	if (NO_DATUM(datum)) {
196*9517SBill.Taylor@Sun.COM 		/*
197*9517SBill.Taylor@Sun.COM 		 * Reserved value used for datum
198*9517SBill.Taylor@Sun.COM 		 */
199*9517SBill.Taylor@Sun.COM 		dapl_dbg_log(
200*9517SBill.Taylor@Sun.COM 		    DAPL_DBG_TYPE_ERR,
201*9517SBill.Taylor@Sun.COM 		    "dapli_hash_add () called with magic NO_DATA value "
202*9517SBill.Taylor@Sun.COM 		    "(%p) used as datum!\n", datum);
203*9517SBill.Taylor@Sun.COM 		return (DAT_FALSE);
204*9517SBill.Taylor@Sun.COM 	}
205*9517SBill.Taylor@Sun.COM 
206*9517SBill.Taylor@Sun.COM 	DAPL_HASHLOOKUP(p_table, key, olddatum, found);
207*9517SBill.Taylor@Sun.COM 
208*9517SBill.Taylor@Sun.COM 	if (found) {
209*9517SBill.Taylor@Sun.COM 		/*
210*9517SBill.Taylor@Sun.COM 		 * key exists already
211*9517SBill.Taylor@Sun.COM 		 */
212*9517SBill.Taylor@Sun.COM 		if (report_dup) {
213*9517SBill.Taylor@Sun.COM 			*report_dup = DAT_TRUE;
214*9517SBill.Taylor@Sun.COM 		}
215*9517SBill.Taylor@Sun.COM 
216*9517SBill.Taylor@Sun.COM 		if (!allow_dup) {
217*9517SBill.Taylor@Sun.COM 			dapl_dbg_log(DAPL_DBG_TYPE_ERR,
218*9517SBill.Taylor@Sun.COM 			    "dapli_hash_add () called with duplicate key "
219*9517SBill.Taylor@Sun.COM 			    "(" F64x ")\n", key);
220*9517SBill.Taylor@Sun.COM 			return (DAT_FALSE);
221*9517SBill.Taylor@Sun.COM 		}
222*9517SBill.Taylor@Sun.COM 	}
223*9517SBill.Taylor@Sun.COM 
224*9517SBill.Taylor@Sun.COM 	hashValue = DAPL_DOHASH(key, p_table->tbl_size);
225*9517SBill.Taylor@Sun.COM 	if (NO_DATUM(p_table->table[hashValue].datum)) {
226*9517SBill.Taylor@Sun.COM 		/*
227*9517SBill.Taylor@Sun.COM 		 * Empty head - just fill it in
228*9517SBill.Taylor@Sun.COM 		 */
229*9517SBill.Taylor@Sun.COM 		p_table->table[hashValue].key = key;
230*9517SBill.Taylor@Sun.COM 		p_table->table[hashValue].datum = datum;
231*9517SBill.Taylor@Sun.COM 		p_table->table[hashValue].next_element = 0;
232*9517SBill.Taylor@Sun.COM 		p_table->num_entries++;
233*9517SBill.Taylor@Sun.COM 		status = DAT_TRUE;
234*9517SBill.Taylor@Sun.COM 	} else {
235*9517SBill.Taylor@Sun.COM 		DAPL_HASH_ELEM *newelement = (DAPL_HASH_ELEM *)
236*9517SBill.Taylor@Sun.COM 		    dapl_os_alloc(sizeof (DAPL_HASH_ELEM));
237*9517SBill.Taylor@Sun.COM 		/*
238*9517SBill.Taylor@Sun.COM 		 * Add an element to the end of the chain
239*9517SBill.Taylor@Sun.COM 		 */
240*9517SBill.Taylor@Sun.COM 		if (newelement) {
241*9517SBill.Taylor@Sun.COM 			DAPL_HASH_ELEM *lastelement;
242*9517SBill.Taylor@Sun.COM 			newelement->key = key;
243*9517SBill.Taylor@Sun.COM 			newelement->datum = datum;
244*9517SBill.Taylor@Sun.COM 			newelement->next_element = 0;
245*9517SBill.Taylor@Sun.COM 			for (lastelement = &p_table->table[hashValue];
246*9517SBill.Taylor@Sun.COM 			    lastelement->next_element;
247*9517SBill.Taylor@Sun.COM 			    lastelement = lastelement->next_element) {
248*9517SBill.Taylor@Sun.COM 				/* Walk to the end of the chain */
249*9517SBill.Taylor@Sun.COM 				chain_len++;
250*9517SBill.Taylor@Sun.COM 			}
251*9517SBill.Taylor@Sun.COM 			lastelement->next_element = newelement;
252*9517SBill.Taylor@Sun.COM 			p_table->num_entries++;
253*9517SBill.Taylor@Sun.COM 			status = DAT_TRUE;
254*9517SBill.Taylor@Sun.COM 		} else {
255*9517SBill.Taylor@Sun.COM 			/* allocation failed - should not happen */
256*9517SBill.Taylor@Sun.COM 			status = DAT_FALSE;
257*9517SBill.Taylor@Sun.COM 		}
258*9517SBill.Taylor@Sun.COM 	}
259*9517SBill.Taylor@Sun.COM 
260*9517SBill.Taylor@Sun.COM 	/*
261*9517SBill.Taylor@Sun.COM 	 * Tally up our counters. chain_len is one less than current chain
262*9517SBill.Taylor@Sun.COM 	 * length.
263*9517SBill.Taylor@Sun.COM 	 */
264*9517SBill.Taylor@Sun.COM 	chain_len++;
265*9517SBill.Taylor@Sun.COM 	p_table->hash_tbl_inserts++;
266*9517SBill.Taylor@Sun.COM 	p_table->hash_tbl_total += p_table->num_entries;
267*9517SBill.Taylor@Sun.COM 	p_table->hash_chn_total += chain_len;
268*9517SBill.Taylor@Sun.COM 	if (p_table->num_entries > p_table->hash_tbl_max) {
269*9517SBill.Taylor@Sun.COM 		p_table->hash_tbl_max = p_table->num_entries;
270*9517SBill.Taylor@Sun.COM 	}
271*9517SBill.Taylor@Sun.COM 	if (chain_len > p_table->hash_chn_max) {
272*9517SBill.Taylor@Sun.COM 		p_table->hash_chn_max = chain_len;
273*9517SBill.Taylor@Sun.COM 	}
274*9517SBill.Taylor@Sun.COM 
275*9517SBill.Taylor@Sun.COM 	return (status);
276*9517SBill.Taylor@Sun.COM }
277*9517SBill.Taylor@Sun.COM 
278*9517SBill.Taylor@Sun.COM 
279*9517SBill.Taylor@Sun.COM /*
280*9517SBill.Taylor@Sun.COM  * Remove element from hash bucket
281*9517SBill.Taylor@Sun.COM  *
282*9517SBill.Taylor@Sun.COM  * Inputs:
283*9517SBill.Taylor@Sun.COM  *          element, key        to be deleted
284*9517SBill.Taylor@Sun.COM  * Returns:
285*9517SBill.Taylor@Sun.COM  *          DAT_TRUE on success
286*9517SBill.Taylor@Sun.COM  */
287*9517SBill.Taylor@Sun.COM static DAT_BOOLEAN
dapl_hash_delete_element(DAPL_HASH_ELEM * element,DAPL_HASH_KEY key,DAPL_HASH_DATA * p_datum)288*9517SBill.Taylor@Sun.COM dapl_hash_delete_element(DAPL_HASH_ELEM * element,
289*9517SBill.Taylor@Sun.COM 			DAPL_HASH_KEY key,
290*9517SBill.Taylor@Sun.COM 			DAPL_HASH_DATA *p_datum)
291*9517SBill.Taylor@Sun.COM {
292*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM *curelement;
293*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM *lastelement;
294*9517SBill.Taylor@Sun.COM 
295*9517SBill.Taylor@Sun.COM 	lastelement = NULL;
296*9517SBill.Taylor@Sun.COM 	for (curelement = element; curelement;
297*9517SBill.Taylor@Sun.COM 	    lastelement = curelement,
298*9517SBill.Taylor@Sun.COM 	    curelement = curelement->next_element) {
299*9517SBill.Taylor@Sun.COM 		if (curelement->key == key) {
300*9517SBill.Taylor@Sun.COM 			if (p_datum) {
301*9517SBill.Taylor@Sun.COM 				*p_datum = curelement->datum;
302*9517SBill.Taylor@Sun.COM 			}
303*9517SBill.Taylor@Sun.COM 			if (lastelement) {
304*9517SBill.Taylor@Sun.COM 				/*
305*9517SBill.Taylor@Sun.COM 				 * curelement was malloc'd; free it
306*9517SBill.Taylor@Sun.COM 				 */
307*9517SBill.Taylor@Sun.COM 				lastelement->next_element =
308*9517SBill.Taylor@Sun.COM 				    curelement->next_element;
309*9517SBill.Taylor@Sun.COM 				dapl_os_free((void *) curelement,
310*9517SBill.Taylor@Sun.COM 				    sizeof (DAPL_HASH_ELEM));
311*9517SBill.Taylor@Sun.COM 			} else {
312*9517SBill.Taylor@Sun.COM 				/*
313*9517SBill.Taylor@Sun.COM 				 * curelement is static list head
314*9517SBill.Taylor@Sun.COM 				 */
315*9517SBill.Taylor@Sun.COM 				DAPL_HASH_ELEM *n = curelement->next_element;
316*9517SBill.Taylor@Sun.COM 				if (n) {
317*9517SBill.Taylor@Sun.COM 					/*
318*9517SBill.Taylor@Sun.COM 					 * If there is a next element, copy its
319*9517SBill.Taylor@Sun.COM 					 * contents into the head and free the
320*9517SBill.Taylor@Sun.COM 					 * original next element.
321*9517SBill.Taylor@Sun.COM 					 */
322*9517SBill.Taylor@Sun.COM 					curelement->key = n->key;
323*9517SBill.Taylor@Sun.COM 					curelement->datum = n->datum;
324*9517SBill.Taylor@Sun.COM 					curelement->next_element =
325*9517SBill.Taylor@Sun.COM 					    n->next_element;
326*9517SBill.Taylor@Sun.COM 					dapl_os_free((void *) n,
327*9517SBill.Taylor@Sun.COM 					    sizeof (DAPL_HASH_ELEM));
328*9517SBill.Taylor@Sun.COM 				} else {
329*9517SBill.Taylor@Sun.COM 					curelement->datum = NO_DATUM_VALUE;
330*9517SBill.Taylor@Sun.COM 				}
331*9517SBill.Taylor@Sun.COM 			}
332*9517SBill.Taylor@Sun.COM 			break;
333*9517SBill.Taylor@Sun.COM 		}
334*9517SBill.Taylor@Sun.COM 	}
335*9517SBill.Taylor@Sun.COM 
336*9517SBill.Taylor@Sun.COM 	return (curelement != NULL ? DAT_TRUE : DAT_FALSE);
337*9517SBill.Taylor@Sun.COM }
338*9517SBill.Taylor@Sun.COM 
339*9517SBill.Taylor@Sun.COM 
340*9517SBill.Taylor@Sun.COM /*
341*9517SBill.Taylor@Sun.COM  *
342*9517SBill.Taylor@Sun.COM  * External Functions
343*9517SBill.Taylor@Sun.COM  *
344*9517SBill.Taylor@Sun.COM  */
345*9517SBill.Taylor@Sun.COM 
346*9517SBill.Taylor@Sun.COM 
347*9517SBill.Taylor@Sun.COM /*
348*9517SBill.Taylor@Sun.COM  * Create a new hash table with at least 'table_size' hash buckets.
349*9517SBill.Taylor@Sun.COM  */
350*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_create(IN DAT_COUNT table_size,IN DAT_BOOLEAN locking_required,OUT DAPL_HASH_TABLE ** pp_table)351*9517SBill.Taylor@Sun.COM dapls_hash_create(
352*9517SBill.Taylor@Sun.COM 	IN DAT_COUNT	table_size,
353*9517SBill.Taylor@Sun.COM 	IN DAT_BOOLEAN	locking_required,
354*9517SBill.Taylor@Sun.COM 	OUT DAPL_HASH_TABLE **pp_table)
355*9517SBill.Taylor@Sun.COM {
356*9517SBill.Taylor@Sun.COM 	DAPL_HASH_TABLE *p_table;
357*9517SBill.Taylor@Sun.COM 	DAT_COUNT	table_length = table_size * sizeof (DAPL_HASH_ELEM);
358*9517SBill.Taylor@Sun.COM 	DAT_RETURN	dat_status;
359*9517SBill.Taylor@Sun.COM 	DAT_COUNT	i;
360*9517SBill.Taylor@Sun.COM 
361*9517SBill.Taylor@Sun.COM 	dapl_os_assert(pp_table);
362*9517SBill.Taylor@Sun.COM 	dat_status = DAT_SUCCESS;
363*9517SBill.Taylor@Sun.COM 
364*9517SBill.Taylor@Sun.COM 	/* Allocate hash table */
365*9517SBill.Taylor@Sun.COM 	p_table = dapl_os_alloc(sizeof (DAPL_HASH_TABLE));
366*9517SBill.Taylor@Sun.COM 	if (NULL == p_table) {
367*9517SBill.Taylor@Sun.COM 		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
368*9517SBill.Taylor@Sun.COM 		    DAT_RESOURCE_MEMORY);
369*9517SBill.Taylor@Sun.COM 		goto bail;
370*9517SBill.Taylor@Sun.COM 	}
371*9517SBill.Taylor@Sun.COM 
372*9517SBill.Taylor@Sun.COM 	/* Init hash table, allocate and init and buckets */
373*9517SBill.Taylor@Sun.COM 	(void) dapl_os_memzero(p_table, sizeof (DAPL_HASH_TABLE));
374*9517SBill.Taylor@Sun.COM 	p_table->tbl_size = table_size;
375*9517SBill.Taylor@Sun.COM 	p_table->table = (DAPL_HASH_ELEM *)dapl_os_alloc(table_length);
376*9517SBill.Taylor@Sun.COM 	if (NULL == p_table->table) {
377*9517SBill.Taylor@Sun.COM 		dapl_os_free(p_table, sizeof (DAPL_HASH_TABLE));
378*9517SBill.Taylor@Sun.COM 		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
379*9517SBill.Taylor@Sun.COM 		    DAT_RESOURCE_MEMORY);
380*9517SBill.Taylor@Sun.COM 		goto bail;
381*9517SBill.Taylor@Sun.COM 	}
382*9517SBill.Taylor@Sun.COM 	/* Init the lock anyways */
383*9517SBill.Taylor@Sun.COM 	dapl_os_lock_init(&p_table->lock);
384*9517SBill.Taylor@Sun.COM 	p_table->locking_required = locking_required;
385*9517SBill.Taylor@Sun.COM 
386*9517SBill.Taylor@Sun.COM 	for (i = 0; i < table_size; i++) {
387*9517SBill.Taylor@Sun.COM 		p_table->table[i].datum = NO_DATUM_VALUE;
388*9517SBill.Taylor@Sun.COM 		p_table->table[i].key   = 0;
389*9517SBill.Taylor@Sun.COM 		p_table->table[i].next_element = 0;
390*9517SBill.Taylor@Sun.COM 	}
391*9517SBill.Taylor@Sun.COM 
392*9517SBill.Taylor@Sun.COM 	*pp_table = p_table;
393*9517SBill.Taylor@Sun.COM 
394*9517SBill.Taylor@Sun.COM bail:
395*9517SBill.Taylor@Sun.COM 	return (dat_status);
396*9517SBill.Taylor@Sun.COM }
397*9517SBill.Taylor@Sun.COM 
398*9517SBill.Taylor@Sun.COM 
399*9517SBill.Taylor@Sun.COM /*
400*9517SBill.Taylor@Sun.COM  * Destroy a hash table
401*9517SBill.Taylor@Sun.COM  */
402*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_free(IN DAPL_HASH_TABLE * p_table)403*9517SBill.Taylor@Sun.COM dapls_hash_free(
404*9517SBill.Taylor@Sun.COM 	IN DAPL_HASH_TABLE *p_table)
405*9517SBill.Taylor@Sun.COM {
406*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table && p_table->table);
407*9517SBill.Taylor@Sun.COM 
408*9517SBill.Taylor@Sun.COM 	dapl_os_lock_destroy(&p_table->lock);
409*9517SBill.Taylor@Sun.COM 	dapl_os_free(p_table->table,
410*9517SBill.Taylor@Sun.COM 	    sizeof (DAPL_HASH_ELEM) * p_table->tbl_size);
411*9517SBill.Taylor@Sun.COM 	dapl_os_free(p_table, sizeof (DAPL_HASH_TABLE));
412*9517SBill.Taylor@Sun.COM 
413*9517SBill.Taylor@Sun.COM 	return (DAT_SUCCESS);
414*9517SBill.Taylor@Sun.COM }
415*9517SBill.Taylor@Sun.COM 
416*9517SBill.Taylor@Sun.COM 
417*9517SBill.Taylor@Sun.COM /*
418*9517SBill.Taylor@Sun.COM  * Returns the number of elements stored in the table
419*9517SBill.Taylor@Sun.COM  */
420*9517SBill.Taylor@Sun.COM 
421*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_size(IN DAPL_HASH_TABLE * p_table,OUT DAT_COUNT * p_size)422*9517SBill.Taylor@Sun.COM dapls_hash_size(
423*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_TABLE  *p_table,
424*9517SBill.Taylor@Sun.COM     OUT DAT_COUNT	*p_size)
425*9517SBill.Taylor@Sun.COM {
426*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table && p_size);
427*9517SBill.Taylor@Sun.COM 
428*9517SBill.Taylor@Sun.COM 	*p_size = p_table->num_entries;
429*9517SBill.Taylor@Sun.COM 
430*9517SBill.Taylor@Sun.COM 	return (DAT_SUCCESS);
431*9517SBill.Taylor@Sun.COM }
432*9517SBill.Taylor@Sun.COM 
433*9517SBill.Taylor@Sun.COM 
434*9517SBill.Taylor@Sun.COM /*
435*9517SBill.Taylor@Sun.COM  * Inserts the specified data into the table with the given key.
436*9517SBill.Taylor@Sun.COM  * Duplicates are not expected, and return in error, having done nothing.
437*9517SBill.Taylor@Sun.COM  */
438*9517SBill.Taylor@Sun.COM 
439*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_insert(IN DAPL_HASH_TABLE * p_table,IN DAPL_HASH_KEY key,IN DAPL_HASH_DATA data)440*9517SBill.Taylor@Sun.COM dapls_hash_insert(
441*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_TABLE  *p_table,
442*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_KEY    key,
443*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_DATA   data)
444*9517SBill.Taylor@Sun.COM {
445*9517SBill.Taylor@Sun.COM 	DAT_RETURN	dat_status;
446*9517SBill.Taylor@Sun.COM 
447*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table);
448*9517SBill.Taylor@Sun.COM 	dat_status = DAT_SUCCESS;
449*9517SBill.Taylor@Sun.COM 
450*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
451*9517SBill.Taylor@Sun.COM 		dapl_os_lock(&p_table->lock);
452*9517SBill.Taylor@Sun.COM 	}
453*9517SBill.Taylor@Sun.COM 
454*9517SBill.Taylor@Sun.COM 	if (!dapli_hash_add(p_table, key, data, DAT_FALSE, NULL)) {
455*9517SBill.Taylor@Sun.COM 		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
456*9517SBill.Taylor@Sun.COM 		    DAT_RESOURCE_MEMORY);
457*9517SBill.Taylor@Sun.COM 	}
458*9517SBill.Taylor@Sun.COM 
459*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
460*9517SBill.Taylor@Sun.COM 		dapl_os_unlock(&p_table->lock);
461*9517SBill.Taylor@Sun.COM 	}
462*9517SBill.Taylor@Sun.COM 
463*9517SBill.Taylor@Sun.COM 	return (dat_status);
464*9517SBill.Taylor@Sun.COM }
465*9517SBill.Taylor@Sun.COM 
466*9517SBill.Taylor@Sun.COM 
467*9517SBill.Taylor@Sun.COM /*
468*9517SBill.Taylor@Sun.COM  * Searches for the given key.  If found,
469*9517SBill.Taylor@Sun.COM  * DAT_SUCCESS is returned and the associated
470*9517SBill.Taylor@Sun.COM  * data is returned in the DAPL_HASH_DATA
471*9517SBill.Taylor@Sun.COM  * pointer if that pointer is not NULL.
472*9517SBill.Taylor@Sun.COM  */
473*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_search(IN DAPL_HASH_TABLE * p_table,IN DAPL_HASH_KEY key,OUT DAPL_HASH_DATA * p_data)474*9517SBill.Taylor@Sun.COM dapls_hash_search(
475*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_TABLE *p_table,
476*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_KEY    key,
477*9517SBill.Taylor@Sun.COM     OUT DAPL_HASH_DATA *p_data)
478*9517SBill.Taylor@Sun.COM {
479*9517SBill.Taylor@Sun.COM 	DAT_RETURN	dat_status;
480*9517SBill.Taylor@Sun.COM 	void		*olddatum;
481*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM	*found;
482*9517SBill.Taylor@Sun.COM 
483*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table);
484*9517SBill.Taylor@Sun.COM 	dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, 0);
485*9517SBill.Taylor@Sun.COM 
486*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
487*9517SBill.Taylor@Sun.COM 		dapl_os_lock(&p_table->lock);
488*9517SBill.Taylor@Sun.COM 		DAPL_HASHLOOKUP(p_table, key, olddatum, found);
489*9517SBill.Taylor@Sun.COM 		dapl_os_unlock(&p_table->lock);
490*9517SBill.Taylor@Sun.COM 	} else {
491*9517SBill.Taylor@Sun.COM 		DAPL_HASHLOOKUP(p_table, key, olddatum, found);
492*9517SBill.Taylor@Sun.COM 	}
493*9517SBill.Taylor@Sun.COM 
494*9517SBill.Taylor@Sun.COM 	if (found) {
495*9517SBill.Taylor@Sun.COM 		if (p_data) {
496*9517SBill.Taylor@Sun.COM 			*p_data = olddatum;
497*9517SBill.Taylor@Sun.COM 		}
498*9517SBill.Taylor@Sun.COM 		dat_status = DAT_SUCCESS;
499*9517SBill.Taylor@Sun.COM 	}
500*9517SBill.Taylor@Sun.COM 
501*9517SBill.Taylor@Sun.COM 	return (dat_status);
502*9517SBill.Taylor@Sun.COM }
503*9517SBill.Taylor@Sun.COM 
504*9517SBill.Taylor@Sun.COM 
505*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_remove(IN DAPL_HASH_TABLE * p_table,IN DAPL_HASH_KEY key,OUT DAPL_HASH_DATA * p_data)506*9517SBill.Taylor@Sun.COM dapls_hash_remove(
507*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_TABLE *p_table,
508*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_KEY key,
509*9517SBill.Taylor@Sun.COM     OUT DAPL_HASH_DATA *p_data)
510*9517SBill.Taylor@Sun.COM {
511*9517SBill.Taylor@Sun.COM 	DAT_RETURN	dat_status;
512*9517SBill.Taylor@Sun.COM 	DAPL_HASH_KEY   hashValue;
513*9517SBill.Taylor@Sun.COM 
514*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table);
515*9517SBill.Taylor@Sun.COM 	dat_status = DAT_ERROR(DAT_INVALID_PARAMETER, 0);
516*9517SBill.Taylor@Sun.COM 
517*9517SBill.Taylor@Sun.COM 	if (p_table->num_entries == 0) {
518*9517SBill.Taylor@Sun.COM 		dapl_dbg_log(DAPL_DBG_TYPE_ERR,
519*9517SBill.Taylor@Sun.COM 		    "dapls_hash_remove () called on empty hash table!\n");
520*9517SBill.Taylor@Sun.COM 		return (dat_status);
521*9517SBill.Taylor@Sun.COM 	}
522*9517SBill.Taylor@Sun.COM 
523*9517SBill.Taylor@Sun.COM 	hashValue = DAPL_DOHASH(key, p_table->tbl_size);
524*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
525*9517SBill.Taylor@Sun.COM 		dapl_os_lock(&p_table->lock);
526*9517SBill.Taylor@Sun.COM 	}
527*9517SBill.Taylor@Sun.COM 	if (dapl_hash_delete_element(&p_table->table[hashValue], key, p_data)) {
528*9517SBill.Taylor@Sun.COM 		p_table->num_entries--;
529*9517SBill.Taylor@Sun.COM 		dat_status = DAT_SUCCESS;
530*9517SBill.Taylor@Sun.COM 	}
531*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
532*9517SBill.Taylor@Sun.COM 		dapl_os_unlock(&p_table->lock);
533*9517SBill.Taylor@Sun.COM 	}
534*9517SBill.Taylor@Sun.COM 	return (dat_status);
535*9517SBill.Taylor@Sun.COM }
536*9517SBill.Taylor@Sun.COM /*
537*9517SBill.Taylor@Sun.COM  * Iterates through the entire hash table return one element at a time.
538*9517SBill.Taylor@Sun.COM  * Note: this is not a threadsafe routine and hence consumers that
539*9517SBill.Taylor@Sun.COM  * rely on the hash-tables internal locking are not allowed to use this.
540*9517SBill.Taylor@Sun.COM  */
541*9517SBill.Taylor@Sun.COM DAT_RETURN
dapls_hash_iterate(IN DAPL_HASH_TABLE * p_table,IN DAPL_HASH_ITERATOR op,OUT DAPL_HASH_DATA * p_data)542*9517SBill.Taylor@Sun.COM dapls_hash_iterate(
543*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_TABLE		*p_table,
544*9517SBill.Taylor@Sun.COM     IN DAPL_HASH_ITERATOR	op,
545*9517SBill.Taylor@Sun.COM     OUT DAPL_HASH_DATA		*p_data)
546*9517SBill.Taylor@Sun.COM {
547*9517SBill.Taylor@Sun.COM 	DAPL_HASH_ELEM *curr;
548*9517SBill.Taylor@Sun.COM 
549*9517SBill.Taylor@Sun.COM 	dapl_os_assert(p_table);
550*9517SBill.Taylor@Sun.COM 	/*
551*9517SBill.Taylor@Sun.COM 	 * sorry iterate is supported only for consumers that do their
552*9517SBill.Taylor@Sun.COM 	 * own locking
553*9517SBill.Taylor@Sun.COM 	 */
554*9517SBill.Taylor@Sun.COM 	if (p_table->locking_required) {
555*9517SBill.Taylor@Sun.COM 		return (DAT_ERROR(DAT_INVALID_PARAMETER, 0));
556*9517SBill.Taylor@Sun.COM 	}
557*9517SBill.Taylor@Sun.COM 	if (op == DAPL_HASH_ITERATE_INIT) {
558*9517SBill.Taylor@Sun.COM 		/* the hash table is empty */
559*9517SBill.Taylor@Sun.COM 		if (p_table->num_entries == 0) {
560*9517SBill.Taylor@Sun.COM 			*p_data = NULL;
561*9517SBill.Taylor@Sun.COM 			return (DAT_SUCCESS);
562*9517SBill.Taylor@Sun.COM 		}
563*9517SBill.Taylor@Sun.COM 		/* find the first bucket with valid data */
564*9517SBill.Taylor@Sun.COM 		p_table->iterator_bucket = 0;
565*9517SBill.Taylor@Sun.COM 		while (p_table->iterator_bucket < p_table->tbl_size) {
566*9517SBill.Taylor@Sun.COM 			curr = &p_table->table[p_table->iterator_bucket];
567*9517SBill.Taylor@Sun.COM 			if (NO_DATUM(curr->datum)) {
568*9517SBill.Taylor@Sun.COM 				/* empty bucket - move on */
569*9517SBill.Taylor@Sun.COM 				p_table->iterator_bucket++;
570*9517SBill.Taylor@Sun.COM 			} else {
571*9517SBill.Taylor@Sun.COM 				break;
572*9517SBill.Taylor@Sun.COM 			}
573*9517SBill.Taylor@Sun.COM 		}
574*9517SBill.Taylor@Sun.COM 		/* should not be empty if num_entries is non-zero */
575*9517SBill.Taylor@Sun.COM 		dapl_os_assert(!NO_DATUM(curr->datum));
576*9517SBill.Taylor@Sun.COM 		if (p_table->iterator_bucket == p_table->tbl_size) {
577*9517SBill.Taylor@Sun.COM 			p_table->iterator = NULL;
578*9517SBill.Taylor@Sun.COM 		} else {
579*9517SBill.Taylor@Sun.COM 			p_table->iterator = curr;
580*9517SBill.Taylor@Sun.COM 		}
581*9517SBill.Taylor@Sun.COM 	} else {
582*9517SBill.Taylor@Sun.COM 		dapl_os_assert(op == DAPL_HASH_ITERATE_NEXT);
583*9517SBill.Taylor@Sun.COM 	}
584*9517SBill.Taylor@Sun.COM 	/* iterator points to the element to be returned */
585*9517SBill.Taylor@Sun.COM 	if (p_table->iterator == NULL) {
586*9517SBill.Taylor@Sun.COM 		/* nothing more left in the hashtable */
587*9517SBill.Taylor@Sun.COM 		*p_data = NULL;
588*9517SBill.Taylor@Sun.COM 		return (DAT_SUCCESS);
589*9517SBill.Taylor@Sun.COM 	}
590*9517SBill.Taylor@Sun.COM 
591*9517SBill.Taylor@Sun.COM 	dapl_dbg_log(DAPL_DBG_TYPE_EP,
592*9517SBill.Taylor@Sun.COM 	    "dapls_hash_iterate: entry found=(%p), bucket(%d)\n",
593*9517SBill.Taylor@Sun.COM 	    p_table->iterator, p_table->iterator_bucket);
594*9517SBill.Taylor@Sun.COM 	*p_data = p_table->iterator->datum;
595*9517SBill.Taylor@Sun.COM 	curr = p_table->iterator;
596*9517SBill.Taylor@Sun.COM 
597*9517SBill.Taylor@Sun.COM 	/* re-position iterator to point to the next valid element */
598*9517SBill.Taylor@Sun.COM 	if (curr->next_element != NULL) { /* found the next element */
599*9517SBill.Taylor@Sun.COM 		p_table->iterator = curr->next_element;
600*9517SBill.Taylor@Sun.COM 		dapl_os_assert(!NO_DATUM(p_table->iterator->datum));
601*9517SBill.Taylor@Sun.COM 	} else {
602*9517SBill.Taylor@Sun.COM 		p_table->iterator = NULL;
603*9517SBill.Taylor@Sun.COM 		/*
604*9517SBill.Taylor@Sun.COM 		 * We are here means we've hit the end of the current bucket,
605*9517SBill.Taylor@Sun.COM 		 * so start searching for next bucket with a valid entry -
606*9517SBill.Taylor@Sun.COM 		 * we only need to look at the head of the bucket
607*9517SBill.Taylor@Sun.COM 		 */
608*9517SBill.Taylor@Sun.COM 		p_table->iterator_bucket++;
609*9517SBill.Taylor@Sun.COM 		while (p_table->iterator_bucket < p_table->tbl_size) {
610*9517SBill.Taylor@Sun.COM 			curr = &p_table->table[p_table->iterator_bucket];
611*9517SBill.Taylor@Sun.COM 			if (NO_DATUM(curr->datum)) {
612*9517SBill.Taylor@Sun.COM 				p_table->iterator_bucket++;
613*9517SBill.Taylor@Sun.COM 			} else {
614*9517SBill.Taylor@Sun.COM 				p_table->iterator = curr;
615*9517SBill.Taylor@Sun.COM 				break;
616*9517SBill.Taylor@Sun.COM 			}
617*9517SBill.Taylor@Sun.COM 		}
618*9517SBill.Taylor@Sun.COM 	}
619*9517SBill.Taylor@Sun.COM 	return (DAT_SUCCESS);
620*9517SBill.Taylor@Sun.COM }
621