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