1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2005 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * Copyright (c) 2008-2014 Cisco Systems, Inc.  All rights reserved.
13  * Copyright (c) 2014-2015 Hewlett-Packard Development Company, LP.
14  *                         All rights reserved.
15  * Copyright (c) 2014-2015 Mellanox Technologies, Inc.
16  *                         All rights reserved.
17  * $COPYRIGHT$
18  *
19  * Additional copyrights may follow
20  *
21  * $HEADER$
22  */
23 
24 #include "opal_config.h"
25 #include <stdint.h>
26 #include <string.h>
27 #include "support.h"
28 #include "opal/class/opal_object.h"
29 #include "opal/class/opal_hash_table.h"
30 #include "opal/runtime/opal.h"
31 #include "opal/constants.h"
32 
33 static FILE *error_out=NULL;
34 
35 char *num_keys[] = {
36     "1234", "1234",
37     "5678", "5678",
38     "12450", "12450",
39     "45623", "45623",
40     NULL
41 };
42 
43 
44 char *str_keys[] = {
45     "foo", "bar",
46     "2", "this cow jumped over the moon",
47     "this is another key", "this is another value",
48     "key key", "value value",
49     NULL
50 };
51 
52 
53 char *perm_keys[] = {
54     "abcdef", "abcdef",
55     "bcdefa", "bcdefa",
56     "cdefab", "cdefab",
57     "defabc", "defabc",
58     "efabcd", "efabcd",
59     "fabcde", "fabcde",
60     "badcfe", "badcfe",
61     "badcef", "badcef",
62     "abdcfe", "abdcfe",
63     "bcdaef", "bcdaef",
64     NULL
65 };
66 
67 /*
68  * This data specifically knows about the April'2014 version of hash tables.
69  * It inserts some keys.
70  * It inserts some more with a capacity offset to generate collisions.
71  * Then it checks the table via traversal.
72  * Then... it removes a key and checks again (via traversal)
73  * and removes another key and re-checks.
74  */
75 static char* remove_keys[] = {
76     "1", "A", "2", "B", "4", "D", "6", "F", "10", "J", NULL, /* insert as-is: ...AB.D.F...J... */
77     "2", "b", "4", "d", "5", "e", "3", "c", NULL, /* insert with capacity-offset: ...ABbDdFec.J... */
78     "ABbDdFecJ",		/* traversal expectation */
79     "4", "ABbdeFcJ",		/* remove D (...ABbdeFc..J...) then expected traversal */
80     "2", "AbcdeFJ",		/* remove B (...AbcdeF...J...) then expected traversal */
81     NULL			/* end removals and expectations */
82 };
83 
84 typedef union {
85     uint32_t uvalue;
86     void *vvalue;
87 } value_t;
88 
validate_table(opal_hash_table_t * table,char * keys[],int is_numeric_keys)89 static void validate_table(opal_hash_table_t *table, char *keys[], int is_numeric_keys)
90 {
91     int         j, ret;
92     value_t value;
93 
94     for ( j = 0; keys[j]; j += 2) {
95         if ( 1 == is_numeric_keys ) {
96             ret = opal_hash_table_get_value_uint32(table, atoi(keys[j]),
97                                                    (void**) &value.uvalue);
98             if (OPAL_SUCCESS != ret) {
99                 test_failure("opal_hash_table_get_value_uint32 failed");
100             }
101         } else {
102             ret = opal_hash_table_get_value_ptr(table, keys[j],
103                                                 strlen(keys[j]),
104                                                 &value.vvalue);
105             if (OPAL_SUCCESS != ret) {
106                 test_failure("opal_hash_table_get_value_ptr failed");
107             }
108         }
109         test_verify_str(keys[j+1], value.vvalue);
110     }
111     test_verify_int(j/2, opal_hash_table_get_size(table));
112 }
113 
114 static void
validate_remove_traversal(opal_hash_table_t * table,const char * expected_chars)115 validate_remove_traversal(opal_hash_table_t * table, const char * expected_chars)
116 {
117     /* all values are single-character strings */
118     /* expected_chars are those single characters as a string */
119     const int debug = 0;	/* turn this on if you want to see the details */
120     int rc, problems = 0;
121     const char * expected_scanner = expected_chars;
122     uint32_t key;
123     void * raw_value;
124     void * node;
125     if (debug) {
126 	fprintf(stderr, "debug: expecting '%s' capacity is %d\n",
127 		expected_chars, (int) table->ht_capacity);
128     }
129     for (rc = opal_hash_table_get_first_key_uint32(table, &key, &raw_value, &node);
130 	 OPAL_SUCCESS == rc;
131 	 rc = opal_hash_table_get_next_key_uint32(table, &key, &raw_value, node, &node)) {
132 	const char * value = (const char *) raw_value;
133 	char expected, actual;
134 	if (debug) {
135 	    fprintf(stderr, "key %d (probe at %d) value '%s' excpected_scanner '%s'\n",
136 		    key, (int) (key%table->ht_capacity), value, expected_scanner);
137 	}
138 	if (1 != strlen(value)) {
139 	    fprintf(stderr, "key %d's value '%s' is not a one-character string\n", key, value);
140 	    problems += 1;
141 	    continue;		/* might as well be completely noisy */
142 	}
143 	if ('\0' == *expected_scanner) {
144 	    fprintf(stderr, "Found key %d value '%s' but not expected!\n", key, value);
145 	    problems += 1;
146 	    continue;
147 	}
148 	expected = *expected_scanner++;
149 	actual = *value;
150 	if (actual != expected) {
151 	    fprintf(stderr, "Expected '%c' but got '%c'\n", expected, actual);
152 	    problems += 1;
153 	    continue;
154 	}
155     }
156     /* final checks */
157     if (OPAL_ERROR != rc) {
158 	fprintf(stderr, "table traversal did not end in OPAL_ERROR?!?\n");
159 	problems += 1;
160     }
161     if ('\0' != *expected_scanner) {
162 	fprintf(stderr, "Still expecting more key/values: '%s'\n", expected_scanner);
163 	problems += 1;
164     }
165 
166     /* resolution */
167     if (problems > 0) {
168 	fflush(stderr);
169 	test_failure("validate_remove_traversal");
170     } else {
171 	test_success();
172     }
173 }
174 
test_htable(opal_hash_table_t * table)175 static void test_htable(opal_hash_table_t *table)
176 {
177     int j;
178     fprintf(error_out, "\nTesting integer keys...\n");
179     for ( j = 0; num_keys[j]; j += 2)
180     {
181         opal_hash_table_set_value_uint32(table, atoi(num_keys[j]), num_keys[j+1]);
182     }
183     validate_table(table, num_keys, 1);
184 
185     /* remove all values for next test */
186     opal_hash_table_remove_all(table);
187     test_verify_int(0, opal_hash_table_get_size(table));
188 
189     fprintf(error_out, "\nTesting string keys...\n");
190     for ( j = 0; str_keys[j]; j += 2)
191     {
192         opal_hash_table_set_value_ptr(table, str_keys[j], strlen(str_keys[j]), str_keys[j+1]);
193     }
194     validate_table(table, str_keys, 0);
195 
196     /* remove all values for next test */
197     opal_hash_table_remove_all(table);
198     test_verify_int(0, opal_hash_table_get_size(table));
199 
200     fprintf(error_out, "\nTesting collision resolution...\n");
201     /* All of the string keys in keys array should
202         have the same hash value. */
203     for ( j = 0; perm_keys[j]; j += 2)
204     {
205         opal_hash_table_set_value_ptr(table, perm_keys[j], strlen(perm_keys[j]), perm_keys[j+1]);
206     }
207 
208     validate_table(table, perm_keys, 0);
209 
210     /* remove all values for next test */
211     opal_hash_table_remove_all(table);
212     test_verify_int(0, opal_hash_table_get_size(table));
213 
214     fprintf(error_out, "\nTesting removal and traversal...\n");
215     j = 0;
216     char * str;
217     while (NULL != (str = remove_keys[j++])) {
218 	opal_hash_table_set_value_uint32(table, atoi(str), remove_keys[j++]);
219     }
220     while (NULL != (str = remove_keys[j++])) {
221 	/* generate collisions */
222 	opal_hash_table_set_value_uint32(table, atoi(str) + table->ht_capacity, remove_keys[j++]);
223     }
224     validate_remove_traversal(table, remove_keys[j++]);
225     while (NULL != (str = remove_keys[j++])) {
226 	opal_hash_table_remove_value_uint32(table, atoi(str));
227 	validate_remove_traversal(table, remove_keys[j++]);
228     }
229 
230     /* remove all values for next test */
231     opal_hash_table_remove_all(table);
232     test_verify_int(0, opal_hash_table_get_size(table));
233 
234     fprintf(error_out, "\n\n");
235 }
236 
237 
test_dynamic(void)238 static void test_dynamic(void)
239 {
240     opal_hash_table_t     *table;
241 
242     table = OBJ_NEW(opal_hash_table_t);
243     if ( NULL == table )
244     {
245         fprintf(error_out, "Error: Unable to create hash table.\n");
246         exit(-1);
247     }
248     fprintf(error_out, "Testing with dynamically created table...\n");
249     opal_hash_table_init(table, 4);
250     test_htable(table);
251 
252     OBJ_RELEASE(table);
253 }
254 
255 
test_static(void)256 static void test_static(void)
257 {
258     opal_hash_table_t     table;
259 
260     OBJ_CONSTRUCT(&table, opal_hash_table_t);
261     opal_hash_table_init(&table, 128);
262 
263     fprintf(error_out, "Testing with statically created table...\n");
264     test_htable(&table);
265 
266     OBJ_DESTRUCT(&table);
267 }
268 
269 
main(int argc,char ** argv)270 int main(int argc, char **argv)
271 {
272     int rc;
273 
274     test_init("opal_hash_table_t");
275 
276     rc = opal_init_util(&argc, &argv);
277     test_verify_int(OPAL_SUCCESS, rc);
278     if (OPAL_SUCCESS != rc) {
279         test_finalize();
280         exit(1);
281     }
282 
283 #ifdef STANDALONE
284     error_out = stderr;
285 #else
286     error_out = fopen( "./opal_hash_table_test_out.txt", "w" );
287     if( error_out == NULL ) error_out = stderr;
288 #endif
289 
290     test_dynamic();
291     test_static();
292 #ifndef STANDALONE
293     fclose( error_out );
294 #endif
295 
296     opal_finalize_util ();
297 
298     return test_finalize();
299 }
300