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