1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997,2008 Oracle.  All rights reserved.
5 *
6 * $Id: MpoolExample.cpp,v 12.8 2008/01/08 20:58:26 bostic Exp $
7 */
8
9#include <sys/types.h>
10
11#include <errno.h>
12#include <fcntl.h>
13#include <iostream>
14#include <fstream>
15#include <stdlib.h>
16#include <string.h>
17#include <time.h>
18
19#include <db_cxx.h>
20
21using std::cout;
22using std::cerr;
23using std::ios;
24using std::ofstream;
25
26#define	MPOOL	"mpool"
27
28int init(const char *, int, int);
29int run(DB_ENV *, int, int, int);
30
31static int usage();
32
33const char *progname = "MpoolExample";			// Program name.
34
35class MpoolExample : public DbEnv
36{
37public:
38	MpoolExample();
39	int initdb(const char *home, int cachesize);
40	int run(int hits, int pagesize, int npages);
41
42private:
43	static const char FileName[];
44
45	// no need for copy and assignment
46	MpoolExample(const MpoolExample &);
47	void operator = (const MpoolExample &);
48};
49
50int main(int argc, char *argv[])
51{
52	int ret;
53	int cachesize = 20 * 1024;
54	int hits = 1000;
55	int npages = 50;
56	int pagesize = 1024;
57
58	for (int i = 1; i < argc; ++i) {
59		if (strcmp(argv[i], "-c") == 0) {
60			if ((cachesize = atoi(argv[++i])) < 20 * 1024)
61				usage();
62		}
63		else if (strcmp(argv[i], "-h") == 0) {
64			if ((hits = atoi(argv[++i])) <= 0)
65				usage();
66		}
67		else if (strcmp(argv[i], "-n") == 0) {
68			if ((npages = atoi(argv[++i])) <= 0)
69				usage();
70		}
71		else if (strcmp(argv[i], "-p") == 0) {
72			if ((pagesize = atoi(argv[++i])) <= 0)
73				usage();
74		}
75		else {
76			usage();
77		}
78	}
79
80	// Initialize the file.
81	if ((ret = init(MPOOL, pagesize, npages)) != 0)
82		return (ret);
83
84	try {
85		MpoolExample app;
86
87		cout << progname
88		     << ": cachesize: " << cachesize
89		     << "; pagesize: " << pagesize
90		     << "; N pages: " << npages << "\n";
91
92		if ((ret = app.initdb(NULL, cachesize)) != 0)
93			return (ret);
94		if ((ret = app.run(hits, pagesize, npages)) != 0)
95			return (ret);
96		cout << "MpoolExample: completed\n";
97		return (EXIT_SUCCESS);
98	}
99	catch (DbException &dbe) {
100		cerr << "MpoolExample: " << dbe.what() << "\n";
101		return (EXIT_FAILURE);
102	}
103}
104
105//
106// init --
107//	Create a backing file.
108//
109int
110init(const char *file, int pagesize, int npages)
111{
112	// Create a file with the right number of pages, and store a page
113	// number on each page.
114	ofstream of(file, ios::out | ios::binary);
115
116	if (of.fail()) {
117		cerr << "MpoolExample: " << file << ": open failed\n";
118		return (EXIT_FAILURE);
119	}
120	char *p = new char[pagesize];
121	memset(p, 0, pagesize);
122
123	// The pages are numbered from 0.
124	for (int cnt = 0; cnt <= npages; ++cnt) {
125		*(db_pgno_t *)p = cnt;
126		of.write(p, pagesize);
127		if (of.fail()) {
128			cerr << "MpoolExample: " << file << ": write failed\n";
129			return (EXIT_FAILURE);
130		}
131	}
132	delete [] p;
133	return (EXIT_SUCCESS);
134}
135
136static int
137usage()
138{
139	cerr << "usage: MpoolExample [-c cachesize] "
140	     << "[-h hits] [-n npages] [-p pagesize]\n";
141	return (EXIT_FAILURE);
142}
143
144// Note: by using DB_CXX_NO_EXCEPTIONS, we get explicit error returns
145// from various methods rather than exceptions so we can report more
146// information with each error.
147//
148MpoolExample::MpoolExample()
149:	DbEnv(DB_CXX_NO_EXCEPTIONS)
150{
151}
152
153int MpoolExample::initdb(const char *home, int cachesize)
154{
155	set_error_stream(&cerr);
156	set_errpfx("MpoolExample");
157	set_cachesize(0, cachesize, 0);
158
159	open(home, DB_CREATE | DB_INIT_MPOOL, 0);
160	return (EXIT_SUCCESS);
161}
162
163//
164// run --
165//	Get a set of pages.
166//
167int
168MpoolExample::run(int hits, int pagesize, int npages)
169{
170	db_pgno_t pageno;
171	int cnt, ret;
172	void *p;
173
174	// Open the file in the environment.
175	DbMpoolFile *mfp;
176
177	if ((ret = memp_fcreate(&mfp, 0)) != 0) {
178		cerr << "MpoolExample: memp_fcreate failed: "
179		     << strerror(ret) << "\n";
180		return (EXIT_FAILURE);
181	}
182	mfp->open(MPOOL, 0, 0, pagesize);
183
184	cout << "retrieve " << hits << " random pages... ";
185
186	srand((unsigned int)time(NULL));
187	for (cnt = 0; cnt < hits; ++cnt) {
188		pageno = (rand() % npages) + 1;
189		if ((ret = mfp->get(&pageno, NULL, 0, &p)) != 0) {
190			cerr << "MpoolExample: unable to retrieve page "
191			     << (unsigned long)pageno << ": "
192			     << strerror(ret) << "\n";
193			return (EXIT_FAILURE);
194		}
195		if (*(db_pgno_t *)p != pageno) {
196			cerr << "MpoolExample: wrong page retrieved ("
197			     << (unsigned long)pageno << " != "
198			     << *(int *)p << ")\n";
199			return (EXIT_FAILURE);
200		}
201		if ((ret = mfp->put(p, DB_PRIORITY_UNCHANGED, 0)) != 0) {
202			cerr << "MpoolExample: unable to return page "
203			     << (unsigned long)pageno << ": "
204			     << strerror(ret) << "\n";
205			return (EXIT_FAILURE);
206		}
207	}
208
209	cout << "successful.\n";
210
211	// Close the pool.
212	if ((ret = close(0)) != 0) {
213		cerr << "MpoolExample: " << strerror(ret) << "\n";
214		return (EXIT_FAILURE);
215	}
216	return (EXIT_SUCCESS);
217}
218