Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

transapp.cs

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         /* Start a checkpoint thread. */
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         /* Start a logfile removal thread. */
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         /* Open database: Key is fruit class; Data is specific type. */
00066         db_open(dbenv, &db_fruit, "fruit", 0);
00067 
00068         /* Open database: Key is a color; Data is an integer. */
00069         db_open(dbenv, &db_color, "color", 0);
00070 
00071         /*
00072          * Open database:
00073          *      Key is a name; Data is: company name, address, cat breeds.
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          * If the directory exists, we're done.  We do not further check
00101          * the type of the file, DB will fail appropriately if it's the
00102          * wrong type.
00103          */
00104         if (stat(ENV_DIRECTORY, &sb) == 0)
00105                 return;
00106 
00107         /* Create the directory, read/write/access owner only. */
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         /* Create the environment handle. */
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         /* Set up error handling. */
00129         dbenv->set_errpfx(dbenv, "txnapp");
00130         dbenv->set_errfile(dbenv, stderr);
00131 
00132         /* Do deadlock detection internally. */
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          * Open a transactional environment:
00140          *      create if it doesn't exist
00141          *      free-threaded handle
00142          *      run recovery
00143          *      read/write owner only
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         /* Checkpoint once a minute. */
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         /* NOTREACHED */
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         /* Check once every 5 minutes. */
00187         for (;; sleep(300)) {
00188                 /* Get the list of log files. */
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                 /* Remove the log files. */
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         /* NOTREACHED */
00207 }
00208 
00209 void
00210 log_archlist(DB_ENV *dbenv)
00211 {
00212         int ret;
00213         char **begin, **list;
00214 
00215         /* Get the list of database files. */
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         /* Get the list of log files. */
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         /* Create the database handle. */
00247         if ((ret = db_create(&db, dbenv, 0)) != 0) {
00248                 dbenv->err(dbenv, ret, "db_create");
00249                 exit (1);
00250         }
00251 
00252         /* Optionally, turn on duplicate data items. */
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          * Open a database in the environment:
00260          *      create if it doesn't exist
00261          *      free-threaded handle
00262          *      read/write owner only
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         /* Initialization. */
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                 /* Begin the transaction. */
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                 /* Store the value. */
00297                 switch (ret = db->put(db, tid, &key, &data, 0)) {
00298                 case 0:
00299                         /* Success: commit the change. */
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                         /* Deadlock: retry the operation. */
00307                         if ((ret = tid->abort(tid)) != 0) {
00308                                 dbenv->err(dbenv, ret, "DB_TXN->abort");
00309                                 exit (1);
00310                         }
00311                         break;
00312                 default:
00313                         /* Error: run recovery. */
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         /* Initialization. */
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                 /* Begin the transaction. */
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                  * Get the key.  If it exists, we increment the value.  If it
00344                  * doesn't exist, we create it.
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                         /* Deadlock: retry the operation. */
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                         /* Error: run recovery. */
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                 /* Create the new data item. */
00370                 (void)snprintf(buf, sizeof(buf), "%d", original + increment);
00371                 data.data = buf;
00372                 data.size = strlen(buf) + 1;
00373 
00374                 /* Store the new value. */
00375                 switch (ret = dbp->put(dbp, tid, &key, &data, 0)) {
00376                 case 0:
00377                         /* Success: commit the change. */
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                         /* Deadlock: retry the operation. */
00385                         if ((ret = tid->abort(tid)) != 0) {
00386                                 dbenv->err(dbenv, ret, "DB_TXN->abort");
00387                                 exit (1);
00388                         }
00389                         break;
00390                 default:
00391                         /* Error: run recovery. */
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         /* Initialization. */
00410         memset(&key, 0, sizeof(key));
00411         memset(&data, 0, sizeof(data));
00412         key.data = name;
00413         key.size = strlen(name);
00414 
00415 retry:  /* Begin the transaction. */
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         /* Delete any previously existing item. */
00422         switch (ret = db->del(db, tid, &key, 0)) {
00423         case 0:
00424         case DB_NOTFOUND:
00425                 break;
00426         case DB_LOCK_DEADLOCK:
00427                 /* Deadlock: retry the operation. */
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         /* Create a cursor. */
00439         if ((ret = db->cursor(db, tid, &dbc, 0)) != 0) {
00440                 dbenv->err(dbenv, ret, "db->cursor");
00441                 exit (1);
00442         }
00443 
00444         /* Append the items, in order. */
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                         /* Deadlock: retry the operation. */
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                         /* Error: run recovery. */
00468                         dbenv->err(dbenv, ret, "dbc->put: %s/%s", name, s);
00469                         exit (1);
00470                 }
00471         }
00472         va_end(ap);
00473 
00474         /* Success: commit the change. */
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 }

Generated on Sun Dec 25 12:14:24 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2