00001 #include <sys/types.h>
00002 #include <sys/stat.h>
00003
00004 #include <errno.h>
00005 #include <pthread.h>
00006 #include <stdarg.h>
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include <unistd.h>
00010
00011 #include <db.h>
00012
00013 #define ENV_DIRECTORY "TXNAPP"
00014
00015 void add_cat(DB_ENV *, DB *, char *, ...);
00016 void add_color(DB_ENV *, DB *, char *, int);
00017 void add_fruit(DB_ENV *, DB *, char *, char *);
00018 void *checkpoint_thread(void *);
00019 void log_archlist(DB_ENV *);
00020 void *logfile_thread(void *);
00021 void db_open(DB_ENV *, DB **, char *, int);
00022 void env_dir_create(void);
00023 void env_open(DB_ENV **);
00024 void usage(void);
00025
00026 int
00027 main(int argc, char *argv[])
00028 {
00029 extern int optind;
00030 DB *db_cats, *db_color, *db_fruit;
00031 DB_ENV *dbenv;
00032 pthread_t ptid;
00033 int ch, ret;
00034
00035 while ((ch = getopt(argc, argv, "")) != EOF)
00036 switch (ch) {
00037 case '?':
00038 default:
00039 usage();
00040 }
00041 argc -= optind;
00042 argv += optind;
00043
00044 env_dir_create();
00045 env_open(&dbenv);
00046
00047
00048 if ((ret = pthread_create(
00049 &ptid, NULL, checkpoint_thread, (void *)dbenv)) != 0) {
00050 fprintf(stderr,
00051 "txnapp: failed spawning checkpoint thread: %s\n",
00052 strerror(ret));
00053 exit (1);
00054 }
00055
00056
00057 if ((ret = pthread_create(
00058 &ptid, NULL, logfile_thread, (void *)dbenv)) != 0) {
00059 fprintf(stderr,
00060 "txnapp: failed spawning log file removal thread: %s\n",
00061 strerror(ret));
00062 exit (1);
00063 }
00064
00065
00066 db_open(dbenv, &db_fruit, "fruit", 0);
00067
00068
00069 db_open(dbenv, &db_color, "color", 0);
00070
00071
00072
00073
00074
00075 db_open(dbenv, &db_cats, "cats", 1);
00076
00077 add_fruit(dbenv, db_fruit, "apple", "yellow delicious");
00078
00079 add_color(dbenv, db_color, "blue", 0);
00080 add_color(dbenv, db_color, "blue", 3);
00081
00082 add_cat(dbenv, db_cats,
00083 "Amy Adams",
00084 "Sleepycat Software",
00085 "394 E. Riding Dr., Carlisle, MA 01741, USA",
00086 "abyssinian",
00087 "bengal",
00088 "chartreaux",
00089 NULL);
00090
00091 return (0);
00092 }
00093
00094 void
00095 env_dir_create()
00096 {
00097 struct stat sb;
00098
00099
00100
00101
00102
00103
00104 if (stat(ENV_DIRECTORY, &sb) == 0)
00105 return;
00106
00107
00108 if (mkdir(ENV_DIRECTORY, S_IRWXU) != 0) {
00109 fprintf(stderr,
00110 "txnapp: mkdir: %s: %s\n", ENV_DIRECTORY, strerror(errno));
00111 exit (1);
00112 }
00113 }
00114
00115 void
00116 env_open(DB_ENV **dbenvp)
00117 {
00118 DB_ENV *dbenv;
00119 int ret;
00120
00121
00122 if ((ret = db_env_create(&dbenv, 0)) != 0) {
00123 fprintf(stderr,
00124 "txnapp: db_env_create: %s\n", db_strerror(ret));
00125 exit (1);
00126 }
00127
00128
00129 dbenv->set_errpfx(dbenv, "txnapp");
00130 dbenv->set_errfile(dbenv, stderr);
00131
00132
00133 if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT)) != 0) {
00134 dbenv->err(dbenv, ret, "set_lk_detect: DB_LOCK_DEFAULT");
00135 exit (1);
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145 if ((ret = dbenv->open(dbenv, ENV_DIRECTORY,
00146 DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG |
00147 DB_INIT_MPOOL | DB_INIT_TXN | DB_RECOVER | DB_THREAD,
00148 S_IRUSR | S_IWUSR)) != 0) {
00149 dbenv->err(dbenv, ret, "dbenv->open: %s", ENV_DIRECTORY);
00150 exit (1);
00151 }
00152
00153 *dbenvp = dbenv;
00154 }
00155
00156 void *
00157 checkpoint_thread(void *arg)
00158 {
00159 DB_ENV *dbenv;
00160 int ret;
00161
00162 dbenv = arg;
00163 dbenv->errx(dbenv, "Checkpoint thread: %lu", (u_long)pthread_self());
00164
00165
00166 for (;; sleep(60))
00167 if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0)) != 0) {
00168 dbenv->err(dbenv, ret, "checkpoint thread");
00169 exit (1);
00170 }
00171
00172
00173 }
00174
00175 void *
00176 logfile_thread(void *arg)
00177 {
00178 DB_ENV *dbenv;
00179 int ret;
00180 char **begin, **list;
00181
00182 dbenv = arg;
00183 dbenv->errx(dbenv,
00184 "Log file removal thread: %lu", (u_long)pthread_self());
00185
00186
00187 for (;; sleep(300)) {
00188
00189 if ((ret =
00190 dbenv->log_archive(dbenv, &list, DB_ARCH_ABS)) != 0) {
00191 dbenv->err(dbenv, ret, "DB_ENV->log_archive");
00192 exit (1);
00193 }
00194
00195
00196 if (list != NULL) {
00197 for (begin = list; *list != NULL; ++list)
00198 if ((ret = remove(*list)) != 0) {
00199 dbenv->err(dbenv,
00200 ret, "remove %s", *list);
00201 exit (1);
00202 }
00203 free (begin);
00204 }
00205 }
00206
00207 }
00208
00209 void
00210 log_archlist(DB_ENV *dbenv)
00211 {
00212 int ret;
00213 char **begin, **list;
00214
00215
00216 if ((ret = dbenv->log_archive(dbenv,
00217 &list, DB_ARCH_ABS | DB_ARCH_DATA)) != 0) {
00218 dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_DATA");
00219 exit (1);
00220 }
00221 if (list != NULL) {
00222 for (begin = list; *list != NULL; ++list)
00223 printf("database file: %s\n", *list);
00224 free (begin);
00225 }
00226
00227
00228 if ((ret = dbenv->log_archive(dbenv,
00229 &list, DB_ARCH_ABS | DB_ARCH_LOG)) != 0) {
00230 dbenv->err(dbenv, ret, "DB_ENV->log_archive: DB_ARCH_LOG");
00231 exit (1);
00232 }
00233 if (list != NULL) {
00234 for (begin = list; *list != NULL; ++list)
00235 printf("log file: %s\n", *list);
00236 free (begin);
00237 }
00238 }
00239
00240 void
00241 db_open(DB_ENV *dbenv, DB **dbp, char *name, int dups)
00242 {
00243 DB *db;
00244 int ret;
00245
00246
00247 if ((ret = db_create(&db, dbenv, 0)) != 0) {
00248 dbenv->err(dbenv, ret, "db_create");
00249 exit (1);
00250 }
00251
00252
00253 if (dups && (ret = db->set_flags(db, DB_DUP)) != 0) {
00254 dbenv->err(dbenv, ret, "db->set_flags: DB_DUP");
00255 exit (1);
00256 }
00257
00258
00259
00260
00261
00262
00263
00264 if ((ret = db->open(db, NULL, name, NULL, DB_BTREE,
00265 DB_AUTO_COMMIT | DB_CREATE | DB_THREAD, S_IRUSR | S_IWUSR)) != 0) {
00266 (void)db->close(db, 0);
00267 dbenv->err(dbenv, ret, "db->open: %s", name);
00268 exit (1);
00269 }
00270
00271 *dbp = db;
00272 }
00273
00274 void
00275 add_fruit(DB_ENV *dbenv, DB *db, char *fruit, char *name)
00276 {
00277 DBT key, data;
00278 DB_TXN *tid;
00279 int ret;
00280
00281
00282 memset(&key, 0, sizeof(key));
00283 memset(&data, 0, sizeof(data));
00284 key.data = fruit;
00285 key.size = strlen(fruit);
00286 data.data = name;
00287 data.size = strlen(name);
00288
00289 for (;;) {
00290
00291 if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
00292 dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
00293 exit (1);
00294 }
00295
00296
00297 switch (ret = db->put(db, tid, &key, &data, 0)) {
00298 case 0:
00299
00300 if ((ret = tid->commit(tid, 0)) != 0) {
00301 dbenv->err(dbenv, ret, "DB_TXN->commit");
00302 exit (1);
00303 }
00304 return;
00305 case DB_LOCK_DEADLOCK:
00306
00307 if ((ret = tid->abort(tid)) != 0) {
00308 dbenv->err(dbenv, ret, "DB_TXN->abort");
00309 exit (1);
00310 }
00311 break;
00312 default:
00313
00314 dbenv->err(dbenv, ret, "dbc->put: %s/%s", fruit, name);
00315 exit (1);
00316 }
00317 }
00318 }
00319
00320 void
00321 add_color(DB_ENV *dbenv, DB *dbp, char *color, int increment)
00322 {
00323 DBT key, data;
00324 DB_TXN *tid;
00325 int original, ret;
00326 char buf[64];
00327
00328
00329 memset(&key, 0, sizeof(key));
00330 key.data = color;
00331 key.size = strlen(color);
00332 memset(&data, 0, sizeof(data));
00333 data.flags = DB_DBT_MALLOC;
00334
00335 for (;;) {
00336
00337 if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
00338 dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
00339 exit (1);
00340 }
00341
00342
00343
00344
00345
00346 switch (ret = dbp->get(dbp, tid, &key, &data, 0)) {
00347 case 0:
00348 original = atoi(data.data);
00349 break;
00350 case DB_LOCK_DEADLOCK:
00351
00352 if ((ret = tid->abort(tid)) != 0) {
00353 dbenv->err(dbenv, ret, "DB_TXN->abort");
00354 exit (1);
00355 }
00356 continue;
00357 case DB_NOTFOUND:
00358 original = 0;
00359 break;
00360 default:
00361
00362 dbenv->err(
00363 dbenv, ret, "dbc->get: %s/%d", color, increment);
00364 exit (1);
00365 }
00366 if (data.data != NULL)
00367 free(data.data);
00368
00369
00370 (void)snprintf(buf, sizeof(buf), "%d", original + increment);
00371 data.data = buf;
00372 data.size = strlen(buf) + 1;
00373
00374
00375 switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
00376 case 0:
00377
00378 if ((ret = tid->commit(tid, 0)) != 0) {
00379 dbenv->err(dbenv, ret, "DB_TXN->commit");
00380 exit (1);
00381 }
00382 return;
00383 case DB_LOCK_DEADLOCK:
00384
00385 if ((ret = tid->abort(tid)) != 0) {
00386 dbenv->err(dbenv, ret, "DB_TXN->abort");
00387 exit (1);
00388 }
00389 break;
00390 default:
00391
00392 dbenv->err(
00393 dbenv, ret, "dbc->put: %s/%d", color, increment);
00394 exit (1);
00395 }
00396 }
00397 }
00398
00399 void
00400 add_cat(DB_ENV *dbenv, DB *db, char *name, ...)
00401 {
00402 va_list ap;
00403 DBC *dbc;
00404 DBT key, data;
00405 DB_TXN *tid;
00406 int ret;
00407 char *s;
00408
00409
00410 memset(&key, 0, sizeof(key));
00411 memset(&data, 0, sizeof(data));
00412 key.data = name;
00413 key.size = strlen(name);
00414
00415 retry:
00416 if ((ret = dbenv->txn_begin(dbenv, NULL, &tid, 0)) != 0) {
00417 dbenv->err(dbenv, ret, "DB_ENV->txn_begin");
00418 exit (1);
00419 }
00420
00421
00422 switch (ret = db->del(db, tid, &key, 0)) {
00423 case 0:
00424 case DB_NOTFOUND:
00425 break;
00426 case DB_LOCK_DEADLOCK:
00427
00428 if ((ret = tid->abort(tid)) != 0) {
00429 dbenv->err(dbenv, ret, "DB_TXN->abort");
00430 exit (1);
00431 }
00432 goto retry;
00433 default:
00434 dbenv->err(dbenv, ret, "db->del: %s", name);
00435 exit (1);
00436 }
00437
00438
00439 if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
00440 dbenv->err(dbenv, ret, "db->cursor");
00441 exit (1);
00442 }
00443
00444
00445 va_start(ap, name);
00446 while ((s = va_arg(ap, char *)) != NULL) {
00447 data.data = s;
00448 data.size = strlen(s);
00449 switch (ret = dbc->c_put(dbc, &key, &data, DB_KEYLAST)) {
00450 case 0:
00451 break;
00452 case DB_LOCK_DEADLOCK:
00453 va_end(ap);
00454
00455
00456 if ((ret = dbc->c_close(dbc)) != 0) {
00457 dbenv->err(
00458 dbenv, ret, "dbc->c_close");
00459 exit (1);
00460 }
00461 if ((ret = tid->abort(tid)) != 0) {
00462 dbenv->err(dbenv, ret, "DB_TXN->abort");
00463 exit (1);
00464 }
00465 goto retry;
00466 default:
00467
00468 dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s);
00469 exit (1);
00470 }
00471 }
00472 va_end(ap);
00473
00474
00475 if ((ret = dbc->c_close(dbc)) != 0) {
00476 dbenv->err(dbenv, ret, "dbc->c_close");
00477 exit (1);
00478 }
00479 if ((ret = tid->commit(tid, 0)) != 0) {
00480 dbenv->err(dbenv, ret, "DB_TXN->commit");
00481 exit (1);
00482 }
00483 }
00484
00485 void
00486 usage()
00487 {
00488 (void)fprintf(stderr, "usage: txnapp\n");
00489 exit(1);
00490 }