1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ex_mpool.c,v 12.8 2008/01/08 20:58:23 bostic Exp $
7 */
8
9#include <sys/types.h>
10
11#include <errno.h>
12#include <stdlib.h>
13#include <string.h>
14#include <time.h>
15
16#ifdef _WIN32
17extern int getopt(int, char * const *, const char *);
18#else
19#include <unistd.h>
20#endif
21
22#include <db.h>
23
24int	init __P((const char *, int, int, const char *));
25int	run __P((int, int, int, int, const char *));
26int	run_mpool __P((int, int, int, int, const char *));
27int	main __P((int, char *[]));
28int	usage __P((const char *));
29#define	MPOOL	"mpool"					/* File. */
30
31int
32main(argc, argv)
33	int argc;
34	char *argv[];
35{
36	extern char *optarg;
37	extern int optind;
38	int cachesize, ch, hits, npages, pagesize;
39	char *progname;
40
41	cachesize = 20 * 1024;
42	hits = 1000;
43	npages = 50;
44	pagesize = 1024;
45	progname = argv[0];
46	while ((ch = getopt(argc, argv, "c:h:n:p:")) != EOF)
47		switch (ch) {
48		case 'c':
49			if ((cachesize = atoi(optarg)) < 20 * 1024)
50				return (usage(progname));
51			break;
52		case 'h':
53			if ((hits = atoi(optarg)) <= 0)
54				return (usage(progname));
55			break;
56		case 'n':
57			if ((npages = atoi(optarg)) <= 0)
58				return (usage(progname));
59			break;
60		case 'p':
61			if ((pagesize = atoi(optarg)) <= 0)
62				return (usage(progname));
63			break;
64		case '?':
65		default:
66			return (usage(progname));
67		}
68	argc -= optind;
69	argv += optind;
70
71	return (run_mpool(pagesize, cachesize,
72	    hits, npages, progname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
73}
74
75int
76usage(progname)
77	const char *progname;
78{
79	(void)fprintf(stderr,
80	    "usage: %s [-c cachesize] [-h hits] [-n npages] [-p pagesize]\n",
81	    progname);
82	return (EXIT_FAILURE);
83}
84
85int
86run_mpool(pagesize, cachesize, hits, npages, progname)
87	int pagesize, cachesize, hits, npages;
88	const char *progname;
89{
90	int ret;
91
92	/* Initialize the file. */
93	if ((ret = init(MPOOL, pagesize, npages, progname)) != 0)
94		return (ret);
95
96	/* Get the pages. */
97	if ((ret = run(hits, cachesize, pagesize, npages, progname)) != 0)
98		return (ret);
99
100	return (0);
101}
102
103/*
104 * init --
105 *	Create a backing file.
106 */
107int
108init(file, pagesize, npages, progname)
109	const char *file, *progname;
110	int pagesize, npages;
111{
112	FILE *fp;
113	int cnt;
114	char *p;
115
116	/*
117	 * Create a file with the right number of pages, and store a page
118	 * number on each page.
119	 */
120	(void)remove(file);
121	if ((fp = fopen(file, "wb")) == NULL) {
122		fprintf(stderr,
123		    "%s: %s: %s\n", progname, file, strerror(errno));
124		return (1);
125	}
126	if ((p = (char *)malloc(pagesize)) == NULL) {
127		fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
128		return (1);
129	}
130
131	/*
132	 * The pages are numbered from 0, not 1.
133	 *
134	 * Write the index of the page at the beginning of the page in order
135	 * to verify the retrieved page (see run()).
136	 */
137	for (cnt = 0; cnt < npages; ++cnt) {
138		*(db_pgno_t *)p = cnt;
139		if (fwrite(p, pagesize, 1, fp) != 1) {
140			fprintf(stderr,
141			    "%s: %s: %s\n", progname, file, strerror(errno));
142			return (1);
143		}
144	}
145
146	(void)fclose(fp);
147	free(p);
148	return (0);
149}
150
151/*
152 * run --
153 *	Get a set of pages.
154 */
155int
156run(hits, cachesize, pagesize, npages, progname)
157	int hits, cachesize, pagesize, npages;
158	const char *progname;
159{
160	DB_ENV *dbenv;
161	DB_MPOOLFILE *mfp;
162	db_pgno_t pageno;
163	int cnt, ret;
164	void *p;
165
166	dbenv = NULL;
167	mfp = NULL;
168
169	printf("%s: cachesize: %d; pagesize: %d; N pages: %d\n",
170	    progname, cachesize, pagesize, npages);
171
172	/*
173	 * Open a memory pool, specify a cachesize, output error messages
174	 * to stderr.
175	 */
176	if ((ret = db_env_create(&dbenv, 0)) != 0) {
177		fprintf(stderr,
178		    "%s: db_env_create: %s\n", progname, db_strerror(ret));
179		return (1);
180	}
181	dbenv->set_errfile(dbenv, stderr);
182	dbenv->set_errpfx(dbenv, progname);
183#ifdef HAVE_VXWORKS
184	if ((ret = dbenv->set_shm_key(dbenv, VXSHM_KEY)) != 0) {
185		dbenv->err(dbenv, ret, "set_shm_key");
186		return (1);
187	}
188#endif
189
190	/* Set the cachesize. */
191	if ((ret = dbenv->set_cachesize(dbenv, 0, cachesize, 0)) != 0) {
192		dbenv->err(dbenv, ret, "set_cachesize");
193		goto err;
194	}
195
196	/* Open the environment. */
197	if ((ret = dbenv->open(
198	    dbenv, NULL, DB_CREATE | DB_INIT_MPOOL, 0)) != 0) {
199		dbenv->err(dbenv, ret, "DB_ENV->open");
200		goto err;
201	}
202
203	/* Open the file in the environment. */
204	if ((ret = dbenv->memp_fcreate(dbenv, &mfp, 0)) != 0) {
205		dbenv->err(dbenv, ret, "DB_ENV->memp_fcreate: %s", MPOOL);
206		goto err;
207	}
208	if ((ret = mfp->open(mfp, MPOOL, 0, 0, pagesize)) != 0) {
209		dbenv->err(dbenv, ret, "DB_MPOOLFILE->open: %s", MPOOL);
210		goto err;
211	}
212
213	printf("retrieve %d random pages... ", hits);
214
215	srand((u_int)time(NULL));
216	for (cnt = 0; cnt < hits; ++cnt) {
217		pageno = rand() % npages;
218		if ((ret = mfp->get(mfp, &pageno, NULL, 0, &p)) != 0) {
219			dbenv->err(dbenv, ret,
220			    "unable to retrieve page %lu", (u_long)pageno);
221			goto err;
222		}
223		/* Verify the page's number that was written in init(). */
224		if (*(db_pgno_t *)p != pageno) {
225			dbenv->errx(dbenv,
226			    "wrong page retrieved (%lu != %d)",
227			    (u_long)pageno, *(int *)p);
228			goto err;
229		}
230		if ((ret = mfp->put(mfp, p, DB_PRIORITY_UNCHANGED, 0)) != 0) {
231			dbenv->err(dbenv, ret,
232			    "unable to return page %lu", (u_long)pageno);
233			goto err;
234		}
235	}
236
237	printf("successful.\n");
238
239	/* Close the file. */
240	if ((ret = mfp->close(mfp, 0)) != 0) {
241		dbenv->err(dbenv, ret, "DB_MPOOLFILE->close");
242		goto err;
243	}
244
245	/* Close the pool. */
246	if ((ret = dbenv->close(dbenv, 0)) != 0) {
247		fprintf(stderr,
248		    "%s: db_env_create: %s\n", progname, db_strerror(ret));
249		return (1);
250	}
251	return (0);
252
253err:	if (mfp != NULL)
254		(void)mfp->close(mfp, 0);
255	if (dbenv != NULL)
256		(void)dbenv->close(dbenv, 0);
257	return (1);
258}
259