• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/db-4.7.25.NC/docs_src/ref/transapp/
1#include <sys/types.h>
2#include <sys/stat.h>
3
4#include <errno.h>
5#include <pthread.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11#include <db.h>
12
13#define	ENV_DIRECTORY	"TXNAPP"
14
15void  add_cat(DB_ENV *, DB *, char *, ...);
16void  add_color(DB_ENV *, DB *, char *, int);
17void  add_fruit(DB_ENV *, DB *, char *, char *);
18void *checkpoint_thread(void *);
19void  log_archlist(DB_ENV *);
20void *logfile_thread(void *);
21void  db_open(DB_ENV *, DB **, char *, int);
22void  env_dir_create(void);
23void  env_open(DB_ENV **);
24void  usage(void);
25
26int
27main(int argc, char *argv[])
28{
29	extern int optind;
30	DB *db_cats, *db_color, *db_fruit;
31	DB_ENV *dbenv;
32	pthread_t ptid;
33	int ch, ret;
34
35	while ((ch = getopt(argc, argv, "")) != EOF)
36		switch (ch) {
37		case '?':
38		default:
39			usage();
40		}
41	argc -= optind;
42	argv += optind;
43
44	env_dir_create();
45	env_open(&dbenv);
46
47	/* Start a checkpoint thread. */
48	if ((ret = pthread_create(
49	    &ptid, NULL, checkpoint_thread, (void *)dbenv)) != 0) {
50		fprintf(stderr,
51		    "txnapp: failed spawning checkpoint thread: %s\n",
52		    strerror(ret));
53		exit (1);
54	}
55
56	/* Start a logfile removal thread. */
57	if ((ret = pthread_create(
58	    &ptid, NULL, logfile_thread, (void *)dbenv)) != 0) {
59		fprintf(stderr,
60		    "txnapp: failed spawning log file removal thread: %s\n",
61		    strerror(ret));
62		exit (1);
63	}
64
65	/* Open database: Key is fruit class; Data is specific type. */
66	db_open(dbenv, &db_fruit, "fruit", 0);
67
68	/* Open database: Key is a color; Data is an integer. */
69	db_open(dbenv, &db_color, "color", 0);
70
71	/*
72	 * Open database:
73	 *	Key is a name; Data is: company name, address, cat breeds.
74	 */
75	db_open(dbenv, &db_cats, "cats", 1);
76
77	add_fruit(dbenv, db_fruit, "apple", "yellow delicious");
78
79	add_color(dbenv, db_color, "blue", 0);
80	add_color(dbenv, db_color, "blue", 3);
81
82	add_cat(dbenv, db_cats,
83		"Amy Adams",
84		"Oracle",
85		"394 E. Riding Dr., Carlisle, MA 01741, USA",
86		"abyssinian",
87		"bengal",
88		"chartreaux",
89		NULL);
90
91	return (0);
92}
93
94void
95env_dir_create()
96{
97	struct stat sb;
98
99	/*
100	 * If the directory exists, we're done.  We do not further check
101	 * the type of the file, DB will fail appropriately if it's the
102	 * wrong type.
103	 */
104	if (stat(ENV_DIRECTORY, &sb) == 0)
105		return;
106
107	/* Create the directory, read/write/access owner only. */
108	if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) {
109		fprintf(stderr,
110		    "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno));
111		exit (1);
112	}
113}
114
115void
116env_open(DB_ENV **dbenvp)
117{
118	DB_ENV *dbenv;
119	int ret;
120
121	/* Create the environment handle. */
122	if ((ret = db_env_create(&dbenv, 0)) != 0) {
123		fprintf(stderr,
124		    "txnapp: db_env_create: %s\n", db_strerror(ret));
125		exit (1);
126	}
127
128	/* Set up error handling. */
129	dbenv->set_errpfx(dbenv, "txnapp");
130	dbenv->set_errfile(dbenv, stderr);
131
132	/* Do deadlock detection internally. */
133	if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) {
134		dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT");
135		exit (1);
136	}
137
138	/*
139	 * Open a transactional environment:
140	 *	create if it doesn't exist
141	 *	free-threaded handle
142	 *	run recovery
143	 *	read/write owner only
144	 */
145	if ((ret = dbenv->open(dbenv, ENV_DIRECTORY,
146	    DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
147	    DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD,
148	    S_IRUSR | S_IWUSR)) != 0) {
149		dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY);
150		exit (1);
151	}
152
153	*dbenvp = dbenv;
154}
155
156void *
157checkpoint_thread(void *arg)
158{
159	DB_ENV *dbenv;
160	int ret;
161
162	dbenv = arg;
163	dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self());
164
165	/* Checkpoint once a minute. */
166	for (;; sleep(60))
167		if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) {
168			dbenv->err(dbenv, ret, "checkpoint thread");
169			exit (1);
170		}
171
172	/* NOTREACHED */
173}
174
175void *
176logfile_thread(void *arg)
177{
178	DB_ENV *dbenv;
179	int ret;
180	char **begin, **list;
181
182	dbenv = arg;
183	dbenv->errx(dbenv,
184	    "Log file removal thread: %lu", (u_long)pthread_self());
185
186	/* Check once every 5 minutes. */
187	for (;; sleep(300)) {
188		/* Get the list of log files. */
189		if ((ret =
190		    dbenv->log_archive(dbenv, &list, DB_ARCH_ABS)) != 0) {
191			dbenv->err(dbenv, ret, "DB_ENV->log_archive");
192			exit (1);
193		}
194
195		/* Remove the log files. */
196		if (list != NULL) {
197			for (begin = list; *list != NULL; ++list)
198				if ((ret = remove(*list)) != 0) {
199					dbenv->err(dbenv,
200					    ret, "remove %s", *list);
201					exit (1);
202				}
203			free (begin);
204		}
205	}
206	/* NOTREACHED */
207}
208
209void
210log_archlist(DB_ENV *dbenv)
211{
212	int ret;
213	char **begin, **list;
214
215	/* Get the list of database files. */
216	if ((ret = dbenv->log_archive(dbenv,
217	    &list, DB_ARCH_ABS | DB_ARCH_DATA)) != 0) {
218		dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_DATA");
219		exit (1);
220	}
221	if (list != NULL) {
222		for (begin = list; *list != NULL; ++list)
223			printf("database file: %s\n", *list);
224		free (begin);
225	}
226
227	/* Get the list of log files. */
228	if ((ret = dbenv->log_archive(dbenv,
229	    &list, DB_ARCH_ABS | DB_ARCH_LOG)) != 0) {
230		dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_LOG");
231		exit (1);
232	}
233	if (list != NULL) {
234		for (begin = list; *list != NULL; ++list)
235			printf("log file: %s\n", *list);
236		free (begin);
237	}
238}
239
240void
241db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups)
242{
243	DB *db;
244	int ret;
245
246	/* Create the database handle. */
247	if ((ret = db_create(&db, dbenv, 0)) != 0) {
248		dbenv->err(dbenv, ret, "db_create");
249		exit (1);
250	}
251
252	/* Optionally, turn on duplicate data items. */
253	if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) {
254		dbenv->err(dbenv, ret, "db->set_flags: DB_DUP");
255		exit (1);
256	}
257
258	/*
259	 * Open a database in the environment:
260	 *	create if it doesn't exist
261	 *	free-threaded handle
262	 *	read/write owner only
263	 */
264	if ((ret = db->open(db, NULL, name, NULL, DB_BTREE,
265	    DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) {
266		(void)db->close(db, 0);
267		dbenv->err(dbenv, ret, "db->open: %s", name);
268		exit (1);
269	}
270
271	*dbp = db;
272}
273
274void
275add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name)
276{
277	DBT key, data;
278	DB_TXN *tid;
279	int ret;
280
281	/* Initialization. */
282	memset(&key, 0, sizeof(key));
283	memset(&data, 0, sizeof(data));
284	key.data = fruit;
285	key.size = strlen(fruit);
286	data.data = name;
287	data.size = strlen(name);
288
289	for (;;) {
290		/* Begin the transaction. */
291		if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
292			dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
293			exit (1);
294		}
295
296		/* Store the value. */
297		switch (ret = db->put(db, tid, &key, &data, 0)) {
298		case 0:
299			/* Success: commit the change. */
300			if ((ret = tid->commit(tid, 0)) != 0) {
301				dbenv->err(dbenv, ret, "DB_TXN->commit");
302				exit (1);
303			}
304			return;
305		case DB_LOCK_DEADLOCK:
306			/* Deadlock: retry the operation. */
307			if ((ret = tid->abort(tid)) != 0) {
308				dbenv->err(dbenv, ret, "DB_TXN->abort");
309				exit (1);
310			}
311			break;
312		default:
313			/* Error: run recovery. */
314			dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name);
315			exit (1);
316		}
317	}
318}
319
320void
321add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment)
322{
323	DBT key, data;
324	DB_TXN *tid;
325	int original, ret;
326	char buf[64];
327
328	/* Initialization. */
329	memset(&key, 0, sizeof(key));
330	key.data = color;
331	key.size = strlen(color);
332	memset(&data, 0, sizeof(data));
333	data.flags = DB_DBT_MALLOC;
334
335	for (;;) {
336		/* Begin the transaction. */
337		if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
338			dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
339			exit (1);
340		}
341
342		/*
343		 * Get the key.  If it exists, we increment the value.  If it
344		 * doesn't exist, we create it.
345		 */
346		switch (ret = dbp->get(dbp, tid, &key, &data, 0)) {
347		case 0:
348			original = atoi(data.data);
349			break;
350		case DB_LOCK_DEADLOCK:
351			/* Deadlock: retry the operation. */
352			if ((ret = tid->abort(tid)) != 0) {
353				dbenv->err(dbenv, ret, "DB_TXN->abort");
354				exit (1);
355			}
356			continue;
357		case DB_NOTFOUND:
358			original = 0;
359			break;
360		default:
361			/* Error: run recovery. */
362			dbenv->err(
363			    dbenv, ret, "dbc->get: %s/%d", color, increment);
364			exit (1);
365		}
366		if (data.data != NULL)
367			free(data.data);
368
369		/* Create the new data item. */
370		(void)snprintf(buf, sizeof(buf), "%d", original + increment);
371		data.data = buf;
372		data.size = strlen(buf) + 1;
373
374		/* Store the new value. */
375		switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
376		case 0:
377			/* Success: commit the change. */
378			if ((ret = tid->commit(tid, 0)) != 0) {
379				dbenv->err(dbenv, ret, "DB_TXN->commit");
380				exit (1);
381			}
382			return;
383		case DB_LOCK_DEADLOCK:
384			/* Deadlock: retry the operation. */
385			if ((ret = tid->abort(tid)) != 0) {
386				dbenv->err(dbenv, ret, "DB_TXN->abort");
387				exit (1);
388			}
389			break;
390		default:
391			/* Error: run recovery. */
392			dbenv->err(
393			    dbenv, ret, "dbc->put: %s/%d", color, increment);
394			exit (1);
395		}
396	}
397}
398
399void
400add_cat(DB_ENV *dbenv, DB *db, char *name, ...)
401{
402	va_list ap;
403	DBC *dbc;
404	DBT key, data;
405	DB_TXN *tid;
406	int ret;
407	char *s;
408
409	/* Initialization. */
410	memset(&key, 0, sizeof(key));
411	memset(&data, 0, sizeof(data));
412	key.data = name;
413	key.size = strlen(name);
414
415retry:	/* Begin the transaction. */
416	if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
417		dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
418		exit (1);
419	}
420
421	/* Delete any previously existing item. */
422	switch (ret = db->del(db, tid, &key, 0)) {
423	case 0:
424	case DB_NOTFOUND:
425		break;
426	case DB_LOCK_DEADLOCK:
427		/* Deadlock: retry the operation. */
428		if ((ret = tid->abort(tid)) != 0) {
429			dbenv->err(dbenv, ret, "DB_TXN->abort");
430			exit (1);
431		}
432		goto retry;
433	default:
434		dbenv->err(dbenv, ret, "db->del: %s", name);
435		exit (1);
436	}
437
438	/* Create a cursor. */
439	if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
440		dbenv->err(dbenv, ret, "db->cursor");
441		exit (1);
442	}
443
444	/* Append the items, in order. */
445	va_start(ap, name);
446	while ((s = va_arg(ap, char *)) != NULL) {
447		data.data = s;
448		data.size = strlen(s);
449		switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) {
450		case 0:
451			break;
452		case DB_LOCK_DEADLOCK:
453			va_end(ap);
454
455			/* Deadlock: retry the operation. */
456			if ((ret = dbc->c_close(dbc)) != 0) {
457				dbenv->err(
458				    dbenv, ret, "dbc->c_close");
459				exit (1);
460			}
461			if ((ret = tid->abort(tid)) != 0) {
462				dbenv->err(dbenv, ret, "DB_TXN->abort");
463				exit (1);
464			}
465			goto retry;
466		default:
467			/* Error: run recovery. */
468			dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s);
469			exit (1);
470		}
471	}
472	va_end(ap);
473
474	/* Success: commit the change. */
475	if ((ret = dbc->c_close(dbc)) != 0) {
476		dbenv->err(dbenv, ret, "dbc->c_close");
477		exit (1);
478	}
479	if ((ret = tid->commit(tid, 0)) != 0) {
480		dbenv->err(dbenv, ret, "DB_TXN->commit");
481		exit (1);
482	}
483}
484
485void
486usage()
487{
488	(void)fprintf(stderr, "usage: txnapp\n");
489	exit(1);
490}
491