transapp.txt
Upload User: tsgydb
Upload Date: 2007-04-14
Package Size: 10674k
Code Size: 10k
Category:

MySQL

Development Platform:

Visual C++

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