| 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 |
|
|---|
| 14 | static struct tdb_context *db;
|
|---|
| 15 | static GDBM_FILE gdbm;
|
|---|
| 16 |
|
|---|
| 17 | struct timeval tp1,tp2;
|
|---|
| 18 |
|
|---|
| 19 | static void _start_timer(void)
|
|---|
| 20 | {
|
|---|
| 21 | gettimeofday(&tp1,NULL);
|
|---|
| 22 | }
|
|---|
| 23 |
|
|---|
| 24 | static 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 |
|
|---|
| 31 | static void fatal(const char *why)
|
|---|
| 32 | {
|
|---|
| 33 | perror(why);
|
|---|
| 34 | exit(1);
|
|---|
| 35 | }
|
|---|
| 36 |
|
|---|
| 37 | #ifdef PRINTF_ATTRIBUTE
|
|---|
| 38 | static void tdb_log(struct tdb_context *tdb, int level, const char *format, ...) PRINTF_ATTRIBUTE(3,4);
|
|---|
| 39 | #endif
|
|---|
| 40 | static 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 |
|
|---|
| 50 | static 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 |
|
|---|
| 98 | static 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 |
|
|---|
| 111 | static 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 |
|
|---|
| 144 | static 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 |
|
|---|
| 177 | static 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 |
|
|---|
| 186 | static 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 | }
|
|---|