/* a test program for tdb - the trivial database */ #include "replace.h" #include "tdb.h" #include "system/filesys.h" #include "system/time.h" #include <gdbm.h> #define DELETE_PROB 7 #define STORE_PROB 5 static struct tdb_context *db; static GDBM_FILE gdbm; struct timeval tp1,tp2; static void _start_timer(void) { gettimeofday(&tp1,NULL); } static double _end_timer(void) { gettimeofday(&tp2,NULL); return((tp2.tv_sec - tp1.tv_sec) + (tp2.tv_usec - tp1.tv_usec)*1.0e-6); } static void fatal(const char *why) { perror(why); exit(1); } #ifdef PRINTF_ATTRIBUTE static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4); #endif static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stdout, format, ap); va_end(ap); fflush(stdout); } static void compare_db(void) { TDB_DATA d, key, nextkey; datum gd, gkey, gnextkey; key = tdb_firstkey(db); while (key.dptr) { d = tdb_fetch(db, key); gkey.dptr = key.dptr; gkey.dsize = key.dsize; gd = gdbm_fetch(gdbm, gkey); if (!gd.dptr) fatal("key not in gdbm"); if (gd.dsize != d.dsize) fatal("data sizes differ"); if (memcmp(gd.dptr, d.dptr, d.dsize)) { fatal("data differs"); } nextkey = tdb_nextkey(db, key); free(key.dptr); free(d.dptr); free(gd.dptr); key = nextkey; } gkey = gdbm_firstkey(gdbm); while (gkey.dptr) { gd = gdbm_fetch(gdbm, gkey); key.dptr = gkey.dptr; key.dsize = gkey.dsize; d = tdb_fetch(db, key); if (!d.dptr) fatal("key not in db"); if (d.dsize != gd.dsize) fatal("data sizes differ"); if (memcmp(d.dptr, gd.dptr, gd.dsize)) { fatal("data differs"); } gnextkey = gdbm_nextkey(gdbm, gkey); free(gkey.dptr); free(gd.dptr); free(d.dptr); gkey = gnextkey; } } static char *randbuf(int len) { char *buf; int i; buf = (char *)malloc(len+1); for (i=0;i<len;i++) { buf[i] = 'a' + (rand() % 26); } buf[i] = 0; return buf; } static void addrec_db(void) { int klen, dlen; char *k, *d; TDB_DATA key, data; klen = 1 + (rand() % 4); dlen = 1 + (rand() % 100); k = randbuf(klen); d = randbuf(dlen); key.dptr = k; key.dsize = klen+1; data.dptr = d; data.dsize = dlen+1; if (rand() % DELETE_PROB == 0) { tdb_delete(db, key); } else if (rand() % STORE_PROB == 0) { if (tdb_store(db, key, data, TDB_REPLACE) != 0) { fatal("tdb_store failed"); } } else { data = tdb_fetch(db, key); if (data.dptr) free(data.dptr); } free(k); free(d); } static void addrec_gdbm(void) { int klen, dlen; char *k, *d; datum key, data; klen = 1 + (rand() % 4); dlen = 1 + (rand() % 100); k = randbuf(klen); d = randbuf(dlen); key.dptr = k; key.dsize = klen+1; data.dptr = d; data.dsize = dlen+1; if (rand() % DELETE_PROB == 0) { gdbm_delete(gdbm, key); } else if (rand() % STORE_PROB == 0) { if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) { fatal("gdbm_store failed"); } } else { data = gdbm_fetch(gdbm, key); if (data.dptr) free(data.dptr); } free(k); free(d); } static int traverse_fn(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) { #if 0 printf("[%s] [%s]\n", key.dptr, dbuf.dptr); #endif tdb_delete(tdb, key); return 0; } static void merge_test(void) { int i; char keys[5][2]; char tdata[] = "test"; TDB_DATA key, data; for (i = 0; i < 5; i++) { snprintf(keys[i],2, "%d", i); key.dptr = keys[i]; key.dsize = 2; data.dptr = tdata; data.dsize = 4; if (tdb_store(db, key, data, TDB_REPLACE) != 0) { fatal("tdb_store failed"); } } key.dptr = keys[0]; tdb_delete(db, key); key.dptr = keys[4]; tdb_delete(db, key); key.dptr = keys[2]; tdb_delete(db, key); key.dptr = keys[1]; tdb_delete(db, key); key.dptr = keys[3]; tdb_delete(db, key); } int main(int argc, const char *argv[]) { int i, seed=0; int loops = 10000; int num_entries; char test_gdbm[] = "test.gdbm"; unlink("test.gdbm"); db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT | O_TRUNC, 0600); gdbm = gdbm_open(test_gdbm, 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 0600, NULL); if (!db || !gdbm) { fatal("db open failed"); } #if 1 srand(seed); _start_timer(); for (i=0;i<loops;i++) addrec_gdbm(); printf("gdbm got %.2f ops/sec\n", i/_end_timer()); #endif merge_test(); srand(seed); _start_timer(); for (i=0;i<loops;i++) addrec_db(); printf("tdb got %.2f ops/sec\n", i/_end_timer()); if (tdb_validate_freelist(db, &num_entries) == -1) { printf("tdb freelist is corrupt\n"); } else { printf("tdb freelist is good (%d entries)\n", num_entries); } compare_db(); printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); tdb_close(db); gdbm_close(gdbm); return 0; }