19 unsigned int positions
;
20 struct cuckoo_array first
, second
;
23 #define HASH_TABLE_SIZE 3072 /* 3k */
24 #define LOTTERY_MAX 6 /* bytes */
25 #define NAME_LENGTH 17 /* bytes */
27 static sig_atomic_t show_status
, reload_table
;
28 static unsigned long nr_runs
, nr_found
, ulong_max
;
30 static void sig_handler(int signum
)
42 static inline unsigned int tdb_hash(char *name
)
44 unsigned value
; /* Used to compute the hash value. */
45 unsigned i
; /* Used to cycle through random values. */
47 /* Set the initial value from the key size. */
48 for (value
= 0x238F13AF * strlen(name
), i
=0; name
[i
]; i
++)
49 value
= (value
+ (((unsigned char *)name
)[i
] << (i
*5 % 24)));
51 return (1103515243 * value
+ 12345);
54 static inline unsigned int joaat_hash(char *name
)
57 unsigned int hash
= 0;
59 for (i
= 0; i
< (int) strlen(name
); i
++) {
72 static int cuckoo_init(struct cuckoo_tbl
*tbl
, unsigned int positions
)
76 tbl
->first
.array
= malloc(sizeof(void *) * positions
);
77 if (!tbl
->first
.array
)
80 tbl
->second
.array
= malloc(sizeof(void *) * positions
);
81 if (!tbl
->second
.array
) {
82 free(tbl
->first
.array
);
86 for (i
= 0; i
< positions
; i
++)
87 tbl
->first
.array
[i
] = tbl
->second
.array
[i
] = NULL
;
89 tbl
->positions
= positions
;
90 tbl
->size
= tbl
->first
.size
= tbl
->second
.size
= 0;
95 static void cuckoo_destroy(struct cuckoo_tbl
*tbl
)
99 for (i
= 0; i
< tbl
->positions
; i
++) {
100 if (tbl
->first
.array
[i
])
101 free(tbl
->first
.array
[i
]);
103 if (tbl
->second
.array
[i
])
104 free(tbl
->second
.array
[i
]);
107 free(tbl
->first
.array
);
108 free(tbl
->second
.array
);
111 static inline int cuckoo_lookup(struct cuckoo_tbl
*tbl
, char *name
,
116 hash
= tdb_hash(name
) % tbl
->positions
;
117 if (tbl
->first
.array
[hash
] == NULL
)
120 if (!memcmp(tbl
->first
.array
[hash
], name
, NAME_LENGTH
))
123 hash
= joaat_hash(name
) % tbl
->positions
;
124 if (tbl
->second
.array
[hash
] == NULL
)
127 if (!memcmp(tbl
->second
.array
[hash
], name
, NAME_LENGTH
))
138 static int cuckoo_insert(struct cuckoo_tbl
*tbl
, char *name
)
142 unsigned int i
, hash
;
144 ret
= cuckoo_lookup(tbl
, name
, NULL
);
146 /* key already exists */
152 for (i
= 0; i
< tbl
->positions
; i
++) {
154 hash
= tdb_hash(el
) % tbl
->positions
;
155 if (tbl
->first
.array
[hash
] == NULL
) {
156 tbl
->first
.array
[hash
] = el
;
161 tmp
= tbl
->first
.array
[hash
];
162 tbl
->first
.array
[hash
] = el
;
165 hash
= joaat_hash(el
) % tbl
->positions
;
166 if (tbl
->second
.array
[hash
] == NULL
) {
167 tbl
->second
.array
[hash
] = el
;
172 tmp
= tbl
->second
.array
[hash
];
173 tbl
->second
.array
[hash
] = el
;
177 fprintf(stderr
, "Out of Max loop, aborting\n");
186 static struct cuckoo_tbl
*rehash(struct cuckoo_tbl
*tbl
)
190 struct cuckoo_tbl
*new_table
;
192 new_table
= malloc(sizeof(struct cuckoo_tbl
));
196 err
= cuckoo_init(new_table
, tbl
->positions
* 2);
200 for (i
= 0; i
< tbl
->positions
; i
++) {
201 if (tbl
->first
.array
[i
]) {
202 err
= cuckoo_insert(new_table
,
203 tbl
->first
.array
[i
]);
208 if (tbl
->second
.array
[i
]) {
209 err
= cuckoo_insert(new_table
,
210 tbl
->second
.array
[i
]);
227 static void cuckoo_print_stats(struct cuckoo_tbl
*tbl
)
229 printf("\n-> Hash table statistics\n");
230 printf("First table size: %4d\n", tbl
->positions
);
231 printf(" o in use: %4d\n", tbl
->first
.size
);
232 printf(" o free: %4d\n", tbl
->positions
- tbl
->first
.size
);
233 printf("Second table size: %4d\n", tbl
->positions
);
234 printf(" o in use: %4d\n", tbl
->second
.size
);
235 printf(" o free: %4d\n", tbl
->positions
- tbl
->second
.size
);
239 static int cuckoo_load_file(struct cuckoo_tbl
*tbl
, const char *fname
)
244 file
= fopen(fname
, "r");
248 memset(line
, 0, sizeof(line
));
250 while (fgets(line
, sizeof(line
), file
) != NULL
) {
254 if (line
[0] == '#') {
255 if (!strchr(line
, '\n')) {
258 while ((c
= getc(file
)) != '\n')
261 memset(line
, 0, sizeof(line
));
265 p
= strchr(line
, '\n');
275 err
= cuckoo_insert(tbl
, p
);
282 /* else key already exists */
284 memset(line
, 0, sizeof(line
));
291 /* FIXME: duplicated from cuckoo_load_file() */
292 static int cuckoo_self_test(struct cuckoo_tbl
*tbl
, const char *fname
)
298 file
= fopen(fname
, "r");
303 memset(line
, 0, sizeof(line
));
305 while (fgets(line
, sizeof(line
), file
) != NULL
) {
308 if (line
[0] == '#') {
309 if (!strchr(line
, '\n')) {
312 while ((c
= getc(file
)) != '\n')
315 memset(line
, 0, sizeof(line
));
319 p
= strchr(line
, '\n');
323 found
= cuckoo_lookup(tbl
, line
, NULL
);
325 printf(" Could not found: %s\n", line
);
330 memset(line
, 0, sizeof(line
));
335 found
= cuckoo_lookup(tbl
, "aaaaaaaaaaaaaaaaa", NULL
);
337 fprintf(stderr
, "found unknow string\n");
344 static int set_seed(void)
350 fd
= open("/dev/random", O_RDONLY
);
354 bytes
= read(fd
, &seed
, sizeof(seed
));
355 if (bytes
!= sizeof(seed
)) {
362 printf("\n-> Seed: %#X\n", seed
);
369 static void lottery(char *result
, size_t size
)
372 int numbers
[LOTTERY_MAX
];
374 memset(result
, 0, size
);
375 memset(numbers
, -1, sizeof(numbers
));
377 for (i
= 0; i
< LOTTERY_MAX
; i
++) {
381 num
= 1 + (int) (60.0 * (rand() / (RAND_MAX
+ 6.0)));
383 for (j
= 0; j
< i
; j
++)
384 if (numbers
[j
] == num
) {
396 snprintf(result
, size
, "%02d %02d %02d %02d %02d %02d",
397 numbers
[0], numbers
[1], numbers
[2],
398 numbers
[3], numbers
[4], numbers
[5]);
401 static void show_pid(void)
403 printf("-> PID: %d\n\n", getpid());
406 int main(int argc
, char *argv
[])
410 struct cuckoo_tbl table
;
411 char result
[24], *fname
;
417 } else if (argc
== 3) {
421 printf("usage: %s < data-file >\n", argv
[0]);
427 ret
= cuckoo_init(&table
, HASH_TABLE_SIZE
);
429 perror("cuckoo_init()");
434 ret
= cuckoo_load_file(&table
, fname
);
436 perror("cuckoo_load_file()");
441 cuckoo_print_stats(&table
);
444 ret
= cuckoo_self_test(&table
, fname
);
445 printf("Performing self-test: ");
446 ret
? printf("FAILED!\n") : printf("PASSED!\n");
452 perror("set_seed()");
459 signal(SIGUSR1
, sig_handler
);
460 signal(SIGHUP
, sig_handler
);
465 * The following checks will probably make the program
466 * run slower, but I've implemented them because they're
467 * cool features (specially the reload table one).
469 * If you want full speed you should consider measuring
470 * this thing and removing these features if needed.
474 printf("-> Ran %lu (* %lu) times with %lu matches\n",
475 nr_runs
, ulong_max
, nr_found
);
481 * XXX: Reading all the file again isn't a smart
482 * way to do this, we could start reading from
483 * the last line read.
485 ret
= cuckoo_load_file(&table
, argv
[1]);
487 perror("cuckoo_load_file()");
488 fprintf(stderr
, "Aborting reload\n");
490 cuckoo_print_stats(&table
);
494 lottery(result
, sizeof(result
));
496 ret
= cuckoo_lookup(&table
, result
, &hash
);
498 printf("-> HIT in run %lu: [%d] %s\n",
499 nr_runs
, hash
, result
);
503 if (++nr_runs
== ULONG_MAX
) {
504 if (++ulong_max
== ULONG_MAX
) {
505 printf("-> ulong_max blew up [%lu]\n",
514 cuckoo_destroy(&table
);