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