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