1 /*
2 * copyright 2010-2012 Edscott Wilson Garcia (GPL-license)
3 *
4 * This is very simple example program to test 64 bit
5 * functions of the Disk Based Hash (DBH) and
6 * verify correct handling of dbh files greater than
7 * 2 Gb in size (up to 256^8/2).
8
9 * A dbh file is created from a specified filesystem.
10 * Paths are indexed with g_string hash key
11 * Hash key collisions are noted in dbh file COLLISIONS
12 * Hash key<->path associations are noted in dbh file KEY*
13 * Hash key<->file are noted in dbh file INDEX
14 *
15 * usage: ./filesystem path option
16 * Option can be:
17 * "index" (create KEY, COLLISIONS and INDEX dbh files)
18 * "dump" (do a foreach on all records and print summary)
19 * "regen" (recreate INDEX dbh file with optimized fisical structure)
20 * "compare" (compare each file in INDEX with actual file on disk)
21 * "parallel"
22 * "thread"
23 * "fulltest" (all of the above)
24
25 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_LSTAT
31 # define LSTAT lstat
32 #else
33 # define LSTAT stat
34 #endif
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <dbh.h>
39 #include <dirent.h>
40 #include <sys/types.h>
41 #include <inttypes.h>
42
43 #ifdef HAVE_SYS_WAIT_H
44 # include <sys/wait.h>
45 #endif
46
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <errno.h>
51
52 #include <glib.h>
53
54 #define DIRECTORY "testfiles"
55 #define KEY "testfiles/filesystem.key.dbh"
56 #define INDEX "testfiles/filesystem.index.dbh"
57 #define REBUILT "testfiles/filesystem.index.rebuilt.dbh"
58 #define TEST_INDEX "testfiles/parfilesystem.index.dbh"
59 #define COLLISIONS "testfiles/filesystem.collisions.dbh"
60
61 #define HELP \
62 " Options:\n"\
63 " index: Create an index of items within the specified \"path\"\n"\
64 " dump: Recalculate size of data items in DBH table (sweep/fanout)\n"\
65 " regen: Regenerate the DBH table (sweep/fanout)\n"\
66 " thread: Test concurrent light weight process activity\n"\
67 " parallel: Test concurrent heavy weight process activity\n"\
68 " compare: Compare data in DBH table to actual data\n"\
69 " fulltest: All tests\n"\
70 " *To test a DBH table larger than 4 GB, choose a \"path\" with more than 4GB.\n"\
71 " Do not alter any item within \"path\" during the test or error will occur."
72
73
74 typedef struct dump_t{
75 char **argv;
76 int original_count;
77 long long original_sum;
78 long long sum;
79 int which;
80 int count;
81 }dump_t;
82
83
84 static DBHashTable *dbh_key;
85 static
get_hash_key(unsigned char bucket,const char * pre_key)86 gchar *get_hash_key(unsigned char bucket, const char *pre_key){
87 GString *gs = g_string_new(pre_key);
88 gchar *key;
89 key=g_strdup_printf("%c%10u", bucket, g_string_hash(gs));
90 g_string_free(gs, TRUE);
91 return key;
92 }
93
94 static int
read_filesystem(DBHashTable * dbh,const char * path,dump_t * dump_p)95 read_filesystem(DBHashTable *dbh, const char *path, dump_t *dump_p)
96 {
97 DIR *directory;
98 int count = 0;
99 struct dirent *d;
100
101 directory = opendir(path);
102 if(!directory) {
103 fprintf(stderr,"Cannot open %s\n" ,path);
104 return -1;
105 }
106 #define _BSD_SOURCE 1
107 while((d = readdir(directory)) != NULL)
108 {
109
110 char *fullpath=NULL;
111 gchar *key;
112 gboolean is_dir=FALSE;
113 unsigned char bucket='A';
114 if(strcmp(d->d_name, ".")==0) continue;
115 if(strcmp(d->d_name, "..")==0) continue;
116
117
118
119
120 fullpath=g_build_filename(path,d->d_name,NULL);
121
122
123 do {
124 key=get_hash_key(bucket,fullpath);
125 dbh_set_key (dbh,(unsigned char *)key);
126 bucket++;
127 }
128 while(dbh_load(dbh));
129 bucket--;
130 if (bucket > 'A'){
131 printf("HASH colision: %s -> %s\n", key,fullpath);
132 DBHashTable *dbh_inverse=dbh_new(COLLISIONS, NULL, 0);
133 char inverse_key[255];
134 memset(inverse_key,0,255);
135 strncpy(inverse_key,fullpath, 254);
136 dbh_set_key (dbh_inverse,(unsigned char *)inverse_key);
137 dbh_set_size(dbh_inverse,DBH_KEYLENGTH(dbh));
138 dbh_set_data(dbh_inverse,(void *)DBH_KEY(dbh),DBH_KEYLENGTH(dbh));
139 dbh_update(dbh_inverse);
140 dbh_close(dbh_inverse);
141 }
142
143 dbh_set_key (dbh_key,(unsigned char *)key);
144 dbh_set_size(dbh_key,strlen(fullpath)+1);
145 dbh_set_data(dbh_key,(void *)fullpath,strlen(fullpath)+1);
146 dbh_update(dbh_key);
147 struct stat st;
148 if (LSTAT(fullpath,&st)<0){
149 printf("cannot stat %s: %s\n",fullpath,strerror(errno));
150 continue;
151 }
152
153
154 if (S_ISDIR(st.st_mode)) is_dir=TRUE;
155
156 if (!is_dir) {
157
158 if (st.st_size == 0) continue;
159 // Let's put a 100 MB limit for the test.
160 if (st.st_size > 100000000LL) {
161 printf("Skipping %s: file is too big, really (%lld)\n",fullpath, (long long)st.st_size);
162 continue;
163 }
164 if (!S_ISREG(st.st_mode)) {
165 continue;
166 }
167 // This is useful if our data size grows over 1024 B:
168 if (DBH_MAXIMUM_RECORD_SIZE(dbh) < st.st_size) {
169 dbh_set_size(dbh,st.st_size);
170 printf("dbh_set_size set to %lld\n",(long long)st.st_size);
171 }
172 int fd=open(fullpath,O_RDONLY);
173 if (fd < 0) {
174 printf("cannot open %s for read\n",fullpath);
175 continue;
176 }
177 // This works instead of dbh_set_data():
178 if (read(fd,DBH_DATA(dbh),st.st_size) < 0){
179 printf("problem reading %lld bytes from %s\n",
180 (long long)st.st_size,fullpath);
181 close(fd);
182 continue;
183 }
184 close(fd);
185 dbh_set_recordsize(dbh,st.st_size);
186 dbh_update(dbh);
187 dump_p->sum += st.st_size;
188 count++;
189 //fprintf(stderr,"%s\n",fullpath);
190 //
191 }
192 if (is_dir) {
193 int retval;
194 retval = read_filesystem(dbh,fullpath, dump_p);
195 if (retval > 0) count += retval;
196 }
197
198 g_free(fullpath);
199 }
200 closedir(directory);
201 // printf ("%s -> %d files\n",path,count);
202 return (count);
203 }
204
operate(DBHashTable * dbh)205 static void operate (DBHashTable *dbh){
206 dump_t *dump_p = dbh->user_data;
207 dump_p->count++;
208 //sum += strlen((char *)DBH_DATA(dbh));
209 dump_p->sum += DBH_RECORD_SIZE(dbh);
210 }
compare(DBHashTable * dbh)211 static void compare (DBHashTable *dbh){
212 dbh_set_key (dbh_key,(unsigned char *)DBH_KEY(dbh));
213 dbh_load(dbh_key);
214 char *path=DBH_DATA(dbh_key);
215 int fd=open(path,O_RDONLY);
216 if (fd < 0) {
217 printf("cannot open %s for read\n",path);
218 return;
219 }
220 // This works instead of dbh_set_data():
221 struct stat st;
222 LSTAT(path,&st);
223 void *p=malloc(st.st_size);
224 if (p == NULL) {
225 fprintf(stderr, "malloc: %s\n", strerror(errno));
226 exit(1);
227 }
228 if (read(fd,p,st.st_size) < 0){
229 printf("problem reading %lld bytes from %s\n",
230 (long long)st.st_size,path);
231 close(fd);
232 free(p);
233 return;
234 }
235 close(fd);
236 if (memcmp(p,DBH_DATA(dbh),st.st_size) != 0) {
237 printf("%s does not compare!\n",path);
238 } else {
239 static int count=0;
240 if (count++ % 1000 == 0) {
241 printf ("."); fflush(stdout);
242 }
243 }
244 free(p);
245 }
246
247 static int
dump(dump_t * dump_p)248 dump(dump_t *dump_p) {
249 //char **argv, int which, int original_count, long long original_sum){
250 dump_p->count=0; dump_p->sum=0;
251 const char *text;
252 if (dump_p->which) text = "Sweep"; else text = "Fanout";
253 fprintf(stdout,"%s is now being performed by pid %d\n", text, getpid());
254 // PARALLEL SAFE need not be specified on READ_ONLY
255 DBHashTable *dbh=dbh_new(INDEX, NULL, DBH_READ_ONLY);
256 dbh->user_data = dump_p;
257 if (dump_p->which) dbh_foreach_sweep (dbh,operate);
258 else dbh_foreach_fanout (dbh,operate);
259 dbh_close(dbh);
260 if (strcmp(dump_p->argv[2],"fulltest")==0) {
261 if (dump_p->sum != dump_p->original_sum){
262 //g_warning("Original sum does not match %s sum (%I64d != %I64d)\nTest FAILED.\n",
263 g_warning("Original sum does not match %s sum (%lld != %lld)\nTest FAILED.\n",
264 text, dump_p->original_sum, dump_p->sum);
265 exit(1);
266 }
267 if (dump_p->count != dump_p->original_count){
268 g_warning("Original count does not match %s count (%d != %d)\nTest FAILED.\n",
269 text, dump_p->original_count, dump_p->count);
270 exit(1);
271 }
272 }
273 fprintf(stdout,
274 " Sweep data:\n"\
275 " Items in the DBH table (filesystem count) = %d\n"\
276 " Sum of data items size saved in DBH table = %lld\n",
277 dump_p->count, dump_p->sum);
278 if (strcmp(dump_p->argv[2],"fulltest")==0) {
279 fprintf(stderr, "Test %s PASSED\n", text);
280 }
281 return 1;
282 }
283
284 static void
check_files(void)285 check_files(void){
286 if (!g_file_test(INDEX, G_FILE_TEST_EXISTS)){
287 g_warning("Index file %s has not yet been created\n",
288 INDEX);
289 exit(1);
290 }
291 if (!g_file_test(COLLISIONS, G_FILE_TEST_EXISTS)){
292 g_warning("DBH table %s has not yet been created\n",
293 COLLISIONS);
294 exit(1);
295 }
296 if (!g_file_test(KEY, G_FILE_TEST_EXISTS)){
297 g_warning("DBH table %s has not yet been created\n",
298 KEY);
299 exit(1);
300 }
301 }
302
303 DBHashTable *newdbh;
partest(DBHashTable * dbh)304 void partest (DBHashTable *dbh){
305 // Assign key
306 memcpy(newdbh->key, dbh->key, DBH_KEYLENGTH(dbh));
307
308 // Assign record size. This is not implicit with dbh_set_data, why not?
309 dbh_set_recordsize (newdbh, DBH_RECORD_SIZE(dbh));
310
311 // Assign data
312 dbh_set_data (newdbh, dbh->data, DBH_RECORD_SIZE(dbh));
313 // Update record
314 dbh_update(newdbh);
315 }
316
317
318 static void *
parallel_test(void * data)319 parallel_test(void *data){
320 // sweep it.
321 // Open source dbh
322 DBHashTable *dbh;
323 dbh=dbh_new(INDEX, NULL, DBH_PARALLEL_SAFE);
324 if (!dbh) return NULL;
325 newdbh=dbh_new(TEST_INDEX, NULL, DBH_PARALLEL_SAFE);
326 dbh_foreach_sweep (dbh, partest);
327 //dbh_foreach_sweep (dbh,operate);
328 dbh_close(dbh);
329 dbh_close(newdbh);
330 return NULL;
331 }
332
rebuild(DBHashTable * dbh_thread)333 static void rebuild (DBHashTable *dbh_thread){
334 DBHashTable *rebuilt_dbh = dbh_thread->user_data;
335 // Adquire mutex.
336 dbh_mutex_lock(rebuilt_dbh);
337
338 // Copy key and data to rebuilt_dbh
339 dbh_set_key(rebuilt_dbh, DBH_KEY(dbh_thread));
340 dbh_set_recordsize (rebuilt_dbh, DBH_RECORD_SIZE(dbh_thread));
341 dbh_set_data(rebuilt_dbh, DBH_DATA(dbh_thread), DBH_RECORD_SIZE(dbh_thread));
342 // Write to rebuilt dbh
343 dbh_update(rebuilt_dbh);
344 // Release mutex
345 dbh_mutex_unlock(rebuilt_dbh);
346 return;
347 }
348
349 static void *
thread_test_f(gpointer data)350 thread_test_f(gpointer data){
351 // Each thread has its own copy, read-only
352 // Since no thread will be writing, DBH_PARALLEL_SAFE is not necesary.
353 DBHashTable *dbh_thread=dbh_new(INDEX, NULL, DBH_READ_ONLY);
354 // If any lingering locks are left behind by a parallel safe
355 // SIGINT, cleanup:
356 dbh_clear_locks(dbh_thread);
357 // Assign open thread-safe dbh to user_data
358 dbh_thread->user_data = data;
359 // This gets a writelock, only when PARALLEL_SAFE is defined,
360 // which is not necessary here.
361 dbh_foreach_sweep (dbh_thread, rebuild);
362 dbh_close(dbh_thread);
363 return NULL;
364 }
365
366 static void *
thread_dump_f(gpointer data)367 thread_dump_f(gpointer data){
368 dump_t *dump_p = data;
369 int i; for(i=1; i>=0; i--) {dump_p->which = i; dump(dump_p);}
370 g_free(dump_p);
371 return NULL;
372 }
373
374
375
main(int argc,char ** argv)376 int main(int argc, char **argv){
377
378 dump_t dump_v;
379 memset(&dump_v, 0, sizeof(dump_t));
380 if (g_mkdir_with_parents(DIRECTORY, 0770) < 0){
381 if (!g_file_test(DIRECTORY, G_FILE_TEST_IS_DIR)){
382 g_warning("mkdir(%s): %s\n", DIRECTORY, strerror(errno));
383 sleep(5);
384
385 exit(1);
386 }
387 }
388 if (!g_file_test(DIRECTORY, G_FILE_TEST_IS_DIR)){
389 g_warning("Failed test: g_file_test(%s, G_FILE_TEST_IS_DIR)\n",
390 DIRECTORY );
391 sleep(5);
392 exit(1);
393 }
394
395 if (argc < 3) {
396 fprintf(stderr,"insufficient arguments (%d < 3), usage: %s (path) (option)\n%s\n",
397 argc, argv[0], HELP);
398 fprintf(stderr, "\n<return> to continue"); fflush(stderr);
399 char buffer[10];
400 fgets(buffer, 10, stdin);
401 exit(1);
402 }
403 dump_v.argv=argv;
404
405 // This DBH uses more than one bucket in order to handle hashtable
406 // key collisions.
407 // This is done in a single thread, non parallel mode.
408 if (strcmp(argv[2],"index")==0 || strcmp(argv[2],"fulltest")==0) {
409 fprintf(stderr, "/////////////////// DBH generation //////////////////////////\n");
410 fprintf(stdout,"Creating index now, process 0x%x recursively reading %s\n", getpid(), argv[1]);
411 // This table is the bucket index file. The index file is also
412 // the data table.
413 unsigned char key_length = 11;
414 // DBHashTable *dbh=dbh_create(INDEX, key_length);
415 DBHashTable *dbh=dbh_new(INDEX, &key_length, DBH_CREATE);
416 // dbh_key=dbh_create(KEY, key_length);
417 dbh_key=dbh_new(KEY, &key_length, DBH_CREATE);
418 // This table handles collisions. If a path is indexed here (first 254
419 // bytes of the string), then the data element is the actual hash table
420 // key. This avoids a collision with a path that has already been indexed.
421 key_length = 254;
422 // DBHashTable *dbh_inverse=dbh_create(COLLISIONS, key_length);
423 DBHashTable *dbh_inverse=dbh_new(COLLISIONS, &key_length, DBH_CREATE);
424 dbh_close(dbh_inverse);
425 // Read the filesystem data into the DBH table.
426 dump_v.sum = 0;
427 dump_v.original_count=read_filesystem(dbh,argv[1],&dump_v);
428 dump_v.original_sum = dump_v.sum;
429 dbh_close(dbh);
430 dbh_close(dbh_key);
431 fprintf(stdout,
432 " Index created:\n"\
433 " Items in the DBH table (filesystem count) = %d\n"\
434 " Sum of data items size saved in DBH table = %lld\n",
435 dump_v.original_count, dump_v.original_sum);
436 if (strcmp(argv[2],"index")==0) exit(0);
437 }
438 // Full or specific test follows.
439 check_files();
440 // Dump test
441 if (strcmp(argv[2],"dump")==0 || strcmp(argv[2],"fulltest")==0) {
442 // Find out how many items and total size of data records
443 // a sweep/fanout of DBH table will find
444 int i; for(i=1; i>=0; i--) {dump_v.which = i; dump(&dump_v);}
445 }
446
447 // Regen tests
448 if (strcmp(argv[2],"regen")==0 || strcmp(argv[2],"fulltest")==0) {
449 fprintf(stderr, "/////////////////// Serial tests //////////////////////////\n");
450 fprintf(stdout,"Performing regen_sweep now...\n");
451 DBHashTable *dbh;
452 dbh=dbh_new(INDEX, NULL, 0);
453 dbh_regen_sweep(&dbh);
454 dbh_close(dbh);
455 // Find out how many items and total size of data records
456 // a sweep of DBH table will find
457 dump_v.which = 1;
458 dump(&dump_v);
459 fprintf(stdout,"Performing regen_fanout now...\n");
460 dbh=dbh_new(INDEX, NULL, 0);
461 dbh_regen_fanout(&dbh);
462 dbh_close(dbh);
463 // Find out how many items and total size of data records
464 // a sweep of DBH table will find
465 dump_v.which = 0;
466 dump(&dump_v);
467 }
468
469
470 // Parallel test
471 #ifndef HAVE_FORK
472 if (strcmp(argv[2],"parallel_read")==0){
473 fprintf(stdout, "Parallel read test, pid: %d\n", getpid()); fflush(stdout);
474 int i; for(i=1; i>=0; i--){
475 dump_v.which = i;
476 dump(&dump_v);
477 }
478 return(0x0);
479 }
480 if (strcmp(argv[2],"parallel_write")==0){
481 fprintf(stdout, "Parallel write test, pid: %d\n", getpid()); fflush(stdout);
482 parallel_test(NULL);
483 return(0x0);
484 }
485 #endif
486 if (strcmp(argv[2],"parallel")==0 || strcmp(argv[2],"fulltest")==0){
487
488 #define CHILDREN 5
489 #ifdef HAVE_FORK
490 pid_t pid[CHILDREN];
491 #else
492 int pid[CHILDREN];
493 #endif
494 int id;
495 // Read test...
496 fprintf(stderr, "/////////////////// Parallel read tests //////////////////////////\n");
497 fprintf(stdout,"Performing parallel read test on %d processes...\n", CHILDREN);
498 for (id=0; id<CHILDREN; id++){
499 #ifdef HAVE_FORK
500 pid[id] = fork();
501 if (!pid[id]) {
502 int i; for(i=1; i>=0; i--) {dump_v.which = i; dump(&dump_v);}
503 return(0x01);
504 }
505 #else
506 const char *arg[] = {argv[0], argv[1], "parallel_read" ,NULL};
507 pid[id] = _spawnvp(P_NOWAIT, arg[0], arg);
508 #endif
509
510 }
511
512 for (id=0; id<CHILDREN; id++){
513 int status;
514 #ifdef HAVE_FORK
515
516 int p = wait(&status);
517 fprintf(stderr,"read test for process 0x%x done... status=%s\n",
518 (int) p, WIFEXITED(status) && WEXITSTATUS(status)?"PASSED":"FAILED");
519 #else
520 int ret = _cwait(&status, pid[id], 0);
521 fprintf(stderr,"read test for process 0x%x done... (%s)\n",
522 pid[id], (ret < 0)?strerror(errno):"exit OK");
523 #endif
524
525 }
526
527 #ifndef PARALLEL_SAFE
528 fprintf(stderr,"Skipping parallel write tests (not implemented on this platform)...\n");
529 #else
530 fprintf(stderr, "/////////////////// Parallel write tests //////////////////////////\n");
531 fprintf(stdout,"Performing parallel write test on %d processes...\n", CHILDREN);
532 // Write test
533 DBHashTable *dbh;
534 dbh=dbh_new(INDEX, NULL, 0);
535 unsigned char key_length = DBH_KEYLENGTH(dbh);
536 newdbh=dbh_new(TEST_INDEX, &key_length, DBH_CREATE);
537 if (DBH_MAXIMUM_RECORD_SIZE(dbh) > DBH_MAXIMUM_RECORD_SIZE(newdbh)){
538 dbh_set_size (newdbh, DBH_MAXIMUM_RECORD_SIZE(dbh));
539 }
540 dbh_close(dbh);
541 dbh_close(newdbh);
542 for (id=0; id<CHILDREN; id++){
543 #ifdef HAVE_FORK
544 pid[id] = fork();
545 if (!pid[id]) {
546 parallel_test(NULL);
547 return 1;
548 }
549 #else
550 const char *arg[] = {argv[0], argv[1], "parallel_write" ,NULL};
551 pid[id] = _spawnvp(P_NOWAIT, arg[0], arg);
552 #endif
553 }
554 for (id=0; id<CHILDREN; id++){
555 int status;
556 #ifdef HAVE_FORK
557 pid_t p = wait(&status);
558 fprintf(stderr,"write test for process 0x%x done... status=%s\n",
559 (int) p, WIFEXITED(status) && WEXITSTATUS(status)?"PASSED":"FAILED");
560 #else
561 int ret = _cwait(&status, pid[id], 0);
562 fprintf(stderr,"write test for process 0x%x done... (%s)\n",
563 pid[id], (ret < 0)?strerror(errno):"exit OK");
564 #endif
565 }
566 fprintf(stdout,"Verifying integrity of parallel write test output...\n");
567 // Copy newly created index to index.
568
569 if (rename(TEST_INDEX, INDEX) < 0){
570 g_warning("rename (%s, %s): %s\n", TEST_INDEX, INDEX, strerror(errno));
571 }
572
573 //dbh=dbh_open(INDEX);
574 //dbh_regen_sweep(&dbh);
575 //dbh_close(dbh);
576 // Find out how many items and total size of data records
577 // a sweep of DBH table will find
578 int i; for(i=1; i>=0; i--) {dump_v.which = i; dump(&dump_v);}
579
580 #endif
581 }
582
583 #if GLIB_MAJOR_VERSION==2 && GLIB_MINOR_VERSION<32
584 g_thread_init(NULL);
585 #endif
586
587 // Thread test
588 if (strcmp(argv[2],"thread")==0 || strcmp(argv[2],"fulltest")==0){
589 fprintf(stderr, "/////////////////// Thread read test //////////////////////////\n");
590 #define THREADS 6
591 GThread *thread[THREADS];
592
593 int id;
594 for (id=0; id<THREADS; id++){
595 dump_t *dump_p = (dump_t *)malloc(sizeof(dump_t));
596 if (dump_p == NULL) {
597 fprintf(stderr, "malloc: %s\n", strerror(errno));
598 exit(1);
599 }
600 memcpy(dump_p, &dump_v, sizeof(dump_t));
601 #if GLIB_MAJOR_VERSION==2 && GLIB_MINOR_VERSION<32
602 thread[id] = g_thread_create(thread_dump_f, dump_p, TRUE, NULL);
603 #else
604 thread[id] = g_thread_try_new(NULL, thread_dump_f, dump_p, NULL);
605 #endif
606 fprintf(stdout," thread 0x%x started\n", GPOINTER_TO_INT(thread[id]));
607 fflush(stdout);
608 }
609 for (id=0; id<THREADS; id++){
610 if (thread[id]) {
611 g_thread_join(thread[id]);
612 fprintf(stdout," thread 0x%x joined.\n", GPOINTER_TO_INT(thread[id]));
613 fflush(stdout);
614 }
615 }
616
617 fprintf(stderr, "/////////////////// Thread read/write test //////////////////////////\n");
618
619 #if 10
620 // Create empty DBH table:
621 unsigned char k = 11;
622 // DBH_THREAD_SAFE sets up the dbh table mutex for thread safe operation
623 DBHashTable *rebuilt_dbh=dbh_new(REBUILT, &k, DBH_CREATE|DBH_THREAD_SAFE);
624
625 for (id=0; id<THREADS; id++){
626 #if GLIB_MAJOR_VERSION==2 && GLIB_MINOR_VERSION<32
627 thread[id] = g_thread_create(thread_test_f, rebuilt_dbh, TRUE, NULL);
628 #else
629 thread[id] = g_thread_try_new(NULL, thread_test_f, rebuilt_dbh, NULL);
630 #endif
631 fprintf(stdout," thread 0x%x started\n", GPOINTER_TO_INT(thread[id]));
632 fflush(stdout);
633 }
634 for (id=0; id<THREADS; id++){
635 if (thread[id]) {
636 g_thread_join(thread[id]);
637 fprintf(stdout," thread 0x%x joined.\n", GPOINTER_TO_INT(thread[id]));
638 fflush(stdout);
639 }
640 }
641 dbh_close(rebuilt_dbh);
642 rename (REBUILT, INDEX);
643 int i; for(i=1; i>=0; i--) {dump_v.which = i; dump(&dump_v);}
644 #endif
645 }
646 fprintf(stderr, "/////////////////// Final comparison test //////////////////////////\n");
647 // Comparison test
648 if (strcmp(argv[2],"compare")==0 || strcmp(argv[2],"fulltest")==0) {
649 fprintf(stdout,"Performing comparison test now (sweep)...\n");
650 DBHashTable *dbh;
651 dbh=dbh_new(INDEX, NULL, DBH_READ_ONLY);
652 dbh_key=dbh_new(KEY, NULL, DBH_READ_ONLY);
653 dbh_foreach_sweep (dbh,compare);
654 dbh_close(dbh);
655 dbh_close(dbh_key);
656 fprintf(stdout,"\n");
657 fprintf(stderr, "Test PASSED\n");
658
659 fprintf(stdout,"Performing comparison test now (fanout)...\n");
660 dbh=dbh_new(INDEX, NULL, DBH_READ_ONLY);
661 dbh_key=dbh_new(KEY, NULL, DBH_READ_ONLY);
662 dbh_foreach_fanout (dbh,compare);
663 dbh_close(dbh);
664 dbh_close(dbh_key);
665 fprintf(stdout,"\n");
666 fprintf(stderr, "Test PASSED\n");
667
668 }
669 fprintf(stderr, "All tests passed.\n");
670 exit(0);
671 }
672