23 #define HASH_TABLE_SIZE 10240 /* 10k */
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 int ohtbl_init(struct ohtbl
*p
, int positions
)
58 p
->table
= malloc(sizeof(void *) * positions
);
62 for (i
= 0; i
< positions
; i
++)
65 p
->positions
= positions
;
67 p
->size
= p
->nr_collisions
= p
->no_collisions
= 0;
72 static void ohtbl_destroy(struct ohtbl
*p
)
76 for (i
= 0; i
< p
->positions
; i
++)
83 static int ohtbl_lookup(struct ohtbl
*p
, char *name
, unsigned int *h
)
88 hash
= tdb_hash(name
) % p
->positions
;
90 for (i
= 0; i
< p
->positions
; i
++) {
92 if (!memcmp(p
->table
[hash
], name
, NAME_LENGTH
)) {
99 hash
= (hash
+ 1) % p
->positions
;
106 static int ohtbl_insert(struct ohtbl
*p
, char *name
)
111 ret
= ohtbl_lookup(p
, name
, NULL
);
113 /* key already exists */
117 hash
= tdb_hash(name
) % p
->positions
;
119 for (i
= 0; i
< p
->positions
; i
++) {
120 if (!p
->table
[hash
]) {
121 p
->table
[hash
] = (void *) name
;
126 else if (i
> p
->gr_collision
)
133 hash
= (hash
+ 1) % p
->positions
;
140 static void ohtbl_show_stats(struct ohtbl
*p
)
142 float lfactor
, probes
;
144 lfactor
= (float) p
->size
/ p
->positions
;
145 probes
= 1 / (1 - lfactor
);
147 printf("\n-> Hash table statistics\n");
148 printf("Table size: %4d\n", p
->positions
);
149 printf(" o free: %4d\n", p
->positions
- p
->size
);
150 printf(" o in use: %4d\n", p
->size
);
151 printf("Perfect hashing: %4d\n", p
->no_collisions
);
152 printf("Collisions: %4d\n", p
->nr_collisions
);
153 printf(" o nr keys: %4d\n", p
->size
- p
->no_collisions
);
154 printf(" o greater: %4d\n", p
->gr_collision
+ 1);
155 printf("Load factor: %4.2f\n", lfactor
);
156 printf("P. to probe: %4.2f\n\n", probes
);
159 static int ohtbl_load_data_file(struct ohtbl
*table
, const char *fname
)
164 file
= fopen(fname
, "r");
168 memset(line
, 0, sizeof(line
));
170 while (fgets(line
, sizeof(line
), file
) != NULL
) {
174 if (line
[0] == '#') {
175 if (!strchr(line
, '\n')) {
178 while ((c
= getc(file
)) != '\n')
181 memset(line
, 0, sizeof(line
));
185 p
= strchr(line
, '\n');
195 err
= ohtbl_insert(table
, p
);
202 /* else key already exists */
204 memset(line
, 0, sizeof(line
));
211 static int set_seed(void)
217 fd
= open("/dev/random", O_RDONLY
);
221 bytes
= read(fd
, &seed
, sizeof(seed
));
222 if (bytes
!= sizeof(seed
)) {
229 printf("\n-> Seed: %#X\n", seed
);
236 static void lottery(char *result
, size_t size
)
239 int numbers
[LOTTERY_MAX
];
241 memset(result
, 0, size
);
242 memset(numbers
, -1, sizeof(numbers
));
244 for (i
= 0; i
< LOTTERY_MAX
; i
++) {
248 num
= 1 + (int) (60.0 * (rand() / (RAND_MAX
+ 6.0)));
250 for (j
= 0; j
< i
; j
++)
251 if (numbers
[j
] == num
) {
263 snprintf(result
, size
, "%02d %02d %02d %02d %02d %02d",
264 numbers
[0], numbers
[1], numbers
[2],
265 numbers
[3], numbers
[4], numbers
[5]);
268 static void show_pid(void)
270 printf("-> PID: %d\n\n", getpid());
273 int main(int argc
, char *argv
[])
281 printf("usage: %s < data-file >\n", argv
[0]);
287 ret
= ohtbl_init(&table
, HASH_TABLE_SIZE
);
289 perror("ohtabl_init()");
294 ret
= ohtbl_load_data_file(&table
, argv
[1]);
296 perror("ohtbl_load_data_file()");
301 ohtbl_show_stats(&table
);
305 perror("set_seed()");
312 signal(SIGUSR1
, sig_handler
);
313 signal(SIGHUP
, sig_handler
);
318 * The following checks will probably make the program
319 * run slower, but I've implemented them because they're
320 * cool features (specially the reload table one).
322 * If you want full speed you should consider measuring
323 * this thing and removing these features if needed.
327 printf("-> Ran %lu (* %lu) times with %lu matches\n",
328 nr_runs
, ulong_max
, nr_found
);
334 * XXX: Reading all the file again isn't a smart
335 * way to do this, we could start reading from
336 * the last line read.
338 ret
= ohtbl_load_data_file(&table
, argv
[1]);
340 perror("ohtbl_load_data_file()");
341 fprintf(stderr
, "Aborting reload\n");
343 ohtbl_show_stats(&table
);
347 lottery(result
, sizeof(result
));
349 ret
= ohtbl_lookup(&table
, result
, &hash
);
351 printf("-> HIT in run %lu: [%d] %s\n",
352 nr_runs
, hash
, result
);
356 if (++nr_runs
== ULONG_MAX
) {
357 if (++ulong_max
== ULONG_MAX
) {
358 printf("-> ulong_max blew up [%lu]\n",
367 ohtbl_destroy(&table
);