1#include <stdlib.h> 2#include <stdio.h> 3#include <fcntl.h> 4#include <unistd.h> 5#include <string.h> 6#include <fcntl.h> 7#include <stdarg.h> 8#include <sys/mman.h> 9#include <sys/stat.h> 10#include <sys/time.h> 11#include <signal.h> 12#include "tdb.h" 13#include <gdbm.h> 14 15/* a test program for tdb - the trivial database */ 16 17 18 19#define DELETE_PROB 7 20#define STORE_PROB 5 21 22static TDB_CONTEXT *db; 23static GDBM_FILE gdbm; 24 25struct timeval tp1,tp2; 26 27static void start_timer(void) 28{ 29 gettimeofday(&tp1,NULL); 30} 31 32static double end_timer(void) 33{ 34 gettimeofday(&tp2,NULL); 35 return((tp2.tv_sec - tp1.tv_sec) + 36 (tp2.tv_usec - tp1.tv_usec)*1.0e-6); 37} 38 39static void fatal(char *why) 40{ 41 perror(why); 42 exit(1); 43} 44 45static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...) 46{ 47 va_list ap; 48 49 va_start(ap, format); 50 vfprintf(stdout, format, ap); 51 va_end(ap); 52 fflush(stdout); 53} 54 55static void compare_db(void) 56{ 57 TDB_DATA d, key, nextkey; 58 datum gd, gkey, gnextkey; 59 60 key = tdb_firstkey(db); 61 while (key.dptr) { 62 d = tdb_fetch(db, key); 63 gkey.dptr = key.dptr; 64 gkey.dsize = key.dsize; 65 66 gd = gdbm_fetch(gdbm, gkey); 67 68 if (!gd.dptr) fatal("key not in gdbm"); 69 if (gd.dsize != d.dsize) fatal("data sizes differ"); 70 if (memcmp(gd.dptr, d.dptr, d.dsize)) { 71 fatal("data differs"); 72 } 73 74 nextkey = tdb_nextkey(db, key); 75 free(key.dptr); 76 free(d.dptr); 77 free(gd.dptr); 78 key = nextkey; 79 } 80 81 gkey = gdbm_firstkey(gdbm); 82 while (gkey.dptr) { 83 gd = gdbm_fetch(gdbm, gkey); 84 key.dptr = gkey.dptr; 85 key.dsize = gkey.dsize; 86 87 d = tdb_fetch(db, key); 88 89 if (!d.dptr) fatal("key not in db"); 90 if (d.dsize != gd.dsize) fatal("data sizes differ"); 91 if (memcmp(d.dptr, gd.dptr, gd.dsize)) { 92 fatal("data differs"); 93 } 94 95 gnextkey = gdbm_nextkey(gdbm, gkey); 96 free(gkey.dptr); 97 free(gd.dptr); 98 free(d.dptr); 99 gkey = gnextkey; 100 } 101} 102 103static char *randbuf(int len) 104{ 105 char *buf; 106 int i; 107 buf = (char *)malloc(len+1); 108 109 for (i=0;i<len;i++) { 110 buf[i] = 'a' + (rand() % 26); 111 } 112 buf[i] = 0; 113 return buf; 114} 115 116static void addrec_db(void) 117{ 118 int klen, dlen; 119 char *k, *d; 120 TDB_DATA key, data; 121 122 klen = 1 + (rand() % 4); 123 dlen = 1 + (rand() % 100); 124 125 k = randbuf(klen); 126 d = randbuf(dlen); 127 128 key.dptr = k; 129 key.dsize = klen+1; 130 131 data.dptr = d; 132 data.dsize = dlen+1; 133 134 if (rand() % DELETE_PROB == 0) { 135 tdb_delete(db, key); 136 } else if (rand() % STORE_PROB == 0) { 137 if (tdb_store(db, key, data, TDB_REPLACE) != 0) { 138 fatal("tdb_store failed"); 139 } 140 } else { 141 data = tdb_fetch(db, key); 142 if (data.dptr) free(data.dptr); 143 } 144 145 free(k); 146 free(d); 147} 148 149static void addrec_gdbm(void) 150{ 151 int klen, dlen; 152 char *k, *d; 153 datum key, data; 154 155 klen = 1 + (rand() % 4); 156 dlen = 1 + (rand() % 100); 157 158 k = randbuf(klen); 159 d = randbuf(dlen); 160 161 key.dptr = k; 162 key.dsize = klen+1; 163 164 data.dptr = d; 165 data.dsize = dlen+1; 166 167 if (rand() % DELETE_PROB == 0) { 168 gdbm_delete(gdbm, key); 169 } else if (rand() % STORE_PROB == 0) { 170 if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) { 171 fatal("gdbm_store failed"); 172 } 173 } else { 174 data = gdbm_fetch(gdbm, key); 175 if (data.dptr) free(data.dptr); 176 } 177 178 free(k); 179 free(d); 180} 181 182static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) 183{ 184#if 0 185 printf("[%s] [%s]\n", key.dptr, dbuf.dptr); 186#endif 187 tdb_delete(tdb, key); 188 return 0; 189} 190 191static void merge_test(void) 192{ 193 int i; 194 char keys[5][2]; 195 TDB_DATA key, data; 196 197 for (i = 0; i < 5; i++) { 198 sprintf(keys[i], "%d", i); 199 key.dptr = keys[i]; 200 key.dsize = 2; 201 202 data.dptr = "test"; 203 data.dsize = 4; 204 205 if (tdb_store(db, key, data, TDB_REPLACE) != 0) { 206 fatal("tdb_store failed"); 207 } 208 } 209 210 key.dptr = keys[0]; 211 tdb_delete(db, key); 212 key.dptr = keys[4]; 213 tdb_delete(db, key); 214 key.dptr = keys[2]; 215 tdb_delete(db, key); 216 key.dptr = keys[1]; 217 tdb_delete(db, key); 218 key.dptr = keys[3]; 219 tdb_delete(db, key); 220} 221 222int main(int argc, char *argv[]) 223{ 224 int i, seed=0; 225 int loops = 10000; 226 227 unlink("test.gdbm"); 228 229 db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST, 230 O_RDWR | O_CREAT | O_TRUNC, 0600); 231 gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST, 232 0600, NULL); 233 234 if (!db || !gdbm) { 235 fatal("db open failed"); 236 } 237 238 tdb_logging_function(db, tdb_log); 239 240#if 1 241 srand(seed); 242 start_timer(); 243 for (i=0;i<loops;i++) addrec_gdbm(); 244 printf("gdbm got %.2f ops/sec\n", i/end_timer()); 245#endif 246 247 merge_test(); 248 249 srand(seed); 250 start_timer(); 251 for (i=0;i<loops;i++) addrec_db(); 252 printf("tdb got %.2f ops/sec\n", i/end_timer()); 253 254 compare_db(); 255 256 printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); 257 printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL)); 258 259 tdb_close(db); 260 gdbm_close(gdbm); 261 262 return 0; 263} 264