1/*
2 * $Id: b_curwalk.c,v 1.12 2008/02/05 20:43:41 bostic Exp $
3 */
4#include "bench.h"
5
6static int usage(void);
7
8int
9b_curwalk(int argc, char *argv[])
10{
11	extern char *optarg;
12	extern int optind;
13	DB *dbp;
14	DBTYPE type;
15	DBC *dbc;
16	DBT key, data;
17	db_recno_t recno;
18	u_int32_t cachesize, pagesize, walkflags;
19	int ch, i, count, dupcount, j;
20	int prev, ret, skipdupwalk, sorted, walkcount;
21	char *ts, dbuf[32], kbuf[32];
22
23	type = DB_BTREE;
24	cachesize = 10 * MEGABYTE;
25	pagesize = 16 * 1024;
26	count = 100000;
27	dupcount = prev = skipdupwalk = sorted = 0;
28	walkcount = 1000;
29	ts = "Btree";
30	while ((ch = getopt(argc, argv, "C:c:d:P:pSst:w:")) != EOF)
31		switch (ch) {
32		case 'C':
33			cachesize = (u_int32_t)atoi(optarg);
34			break;
35		case 'c':
36			count = atoi(optarg);
37			break;
38		case 'd':
39			dupcount = atoi(optarg);
40			break;
41		case 'P':
42			pagesize = (u_int32_t)atoi(optarg);
43			break;
44		case 'p':
45			prev = 1;
46			break;
47		case 'S':
48			skipdupwalk = 1;
49			break;
50		case 's':
51			sorted = 1;
52			break;
53		case 't':
54			switch (optarg[0]) {
55			case 'B': case 'b':
56				ts = "Btree";
57				type = DB_BTREE;
58				break;
59			case 'H': case 'h':
60				if (b_util_have_hash())
61					return (0);
62				ts = "Hash";
63				type = DB_HASH;
64				break;
65			case 'Q': case 'q':
66				if (b_util_have_queue())
67					return (0);
68				ts = "Queue";
69				type = DB_QUEUE;
70				break;
71			case 'R': case 'r':
72				ts = "Recno";
73				type = DB_RECNO;
74				break;
75			default:
76				return (usage());
77			}
78			break;
79		case 'w':
80			walkcount = atoi(optarg);
81			break;
82		case '?':
83		default:
84			return (usage());
85		}
86	argc -= optind;
87	argv += optind;
88	if (argc != 0)
89		return (usage());
90
91	/*
92	 * Queue and Recno don't support duplicates.
93	 */
94	if (dupcount != 0 && (type == DB_QUEUE || type == DB_RECNO)) {
95		fprintf(stderr,
96		    "b_curwalk: Queue and Recno don't support duplicates\n");
97		return (usage());
98	}
99
100#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
101#define	DB_PREV_NODUP	0
102	/*
103	 * DB_PREV_NODUP wasn't available until after 3.0.55.
104	 *
105	 * For some reason, testing sorted duplicates doesn't work either.
106	 * I don't really care about 3.0.55 any more, just ignore it.
107	 */
108	return (0);
109#endif
110	/* Create the database. */
111	DB_BENCH_ASSERT(db_create(&dbp, NULL, 0) == 0);
112	DB_BENCH_ASSERT(dbp->set_cachesize(dbp, 0, cachesize, 0) == 0);
113	DB_BENCH_ASSERT(dbp->set_pagesize(dbp, pagesize) == 0);
114	dbp->set_errfile(dbp, stderr);
115
116	/* Set record length for Queue. */
117	if (type == DB_QUEUE)
118		DB_BENCH_ASSERT(dbp->set_re_len(dbp, 20) == 0);
119
120	/* Set duplicates flag. */
121	if (dupcount != 0)
122		DB_BENCH_ASSERT(
123		    dbp->set_flags(dbp, sorted ? DB_DUPSORT : DB_DUP) == 0);
124
125#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR >= 1
126	DB_BENCH_ASSERT(dbp->open(
127	    dbp, NULL, TESTFILE, NULL, type, DB_CREATE, 0666) == 0);
128#else
129	DB_BENCH_ASSERT(dbp->open(
130	    dbp, TESTFILE, NULL, type, DB_CREATE, 0666) == 0);
131#endif
132
133	/* Initialize the data. */
134	memset(&key, 0, sizeof(key));
135	memset(&data, 0, sizeof(data));
136
137	/* Insert count in-order key/data pairs. */
138	data.data = dbuf;
139	data.size = 20;
140	if (type == DB_BTREE || type == DB_HASH) {
141		key.size = 10;
142		key.data = kbuf;
143		for (i = 0; i < count; ++i) {
144			(void)snprintf(kbuf, sizeof(kbuf), "%010d", i);
145			for (j = 0; j <= dupcount; ++j) {
146				(void)snprintf(dbuf, sizeof(dbuf), "%020d", j);
147				DB_BENCH_ASSERT(
148				    dbp->put(dbp, NULL, &key, &data, 0) == 0);
149			}
150		}
151	} else {
152		key.data = &recno;
153		key.size = sizeof(recno);
154		for (i = 0, recno = 1; i < count; ++i, ++recno)
155			DB_BENCH_ASSERT(
156			    dbp->put(dbp, NULL, &key, &data, 0) == 0);
157	}
158
159	walkflags = prev ?
160	    (skipdupwalk ? DB_PREV_NODUP : DB_PREV) :
161	    (skipdupwalk ? DB_NEXT_NODUP : DB_NEXT);
162
163	/* Walk the cursor through the tree N times. */
164	TIMER_START;
165	for (i = 0; i < walkcount; ++i) {
166		DB_BENCH_ASSERT(dbp->cursor(dbp, NULL, &dbc, 0) == 0);
167		while ((ret = dbc->c_get(dbc, &key, &data, walkflags)) == 0)
168			;
169		DB_BENCH_ASSERT(ret == DB_NOTFOUND);
170		DB_BENCH_ASSERT(dbc->c_close(dbc) == 0);
171	}
172	TIMER_STOP;
173
174	printf("# %d %s %s cursor of %d 10/20 byte key/data items",
175	    walkcount, ts, prev ?
176	    (skipdupwalk ? "DB_PREV_NODUP" : "DB_PREV") :
177	    (skipdupwalk ? "DB_NEXT_NODUP" : "DB_NEXT"),
178	    count);
179	if (dupcount != 0)
180		printf(" with %d dups", dupcount);
181	printf("\n");
182
183	/*
184	 * An "operation" is traversal of a single key/data pair -- not a
185	 * return of the key/data pair, since some versions of this test
186	 * skip duplicate key/data pairs.
187	 *
188	 * Use a "double" so we don't overflow.
189	 */
190	TIMER_DISPLAY((double)count * walkcount);
191
192	DB_BENCH_ASSERT(dbp->close(dbp, 0) == 0);
193
194	return (EXIT_SUCCESS);
195}
196
197static int
198usage()
199{
200	(void)fprintf(stderr, "%s\n\t%s\n",
201	    "usage: b_curwalk [-pSs] [-C cachesz]",
202	    "[-c cnt] [-d dupcnt] [-P pagesz] [-t type] [-w walkcnt]");
203	return (EXIT_FAILURE);
204}
205