diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
commit | 54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 (patch) | |
tree | 18147b92b969d25ffbe61935fb63035cac820dd0 /db-4.8.30/examples_c/ex_apprec |
Berkeley DB 4.8 with rust build script for linux.
Diffstat (limited to 'db-4.8.30/examples_c/ex_apprec')
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/auto_rebuild | 10 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec.c | 278 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec.h | 24 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec.src | 33 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.c | 140 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.h | 13 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec_autop.c | 65 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec_rec.c | 108 | ||||
-rw-r--r-- | db-4.8.30/examples_c/ex_apprec/ex_apprec_template | 70 |
9 files changed, 741 insertions, 0 deletions
diff --git a/db-4.8.30/examples_c/ex_apprec/auto_rebuild b/db-4.8.30/examples_c/ex_apprec/auto_rebuild new file mode 100644 index 0000000..aadcf64 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/auto_rebuild @@ -0,0 +1,10 @@ +# Script to rebuild automatically generated files for ex_apprec. + +E=../examples_c/ex_apprec + +cd ../../dist +awk -f gen_rec.awk \ + -v source_file=$E/ex_apprec_auto.c \ + -v header_file=$E/ex_apprec_auto.h \ + -v print_file=$E/ex_apprec_autop.c \ + -v template_file=$E/ex_apprec_template < $E/ex_apprec.src diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec.c b/db-4.8.30/examples_c/ex_apprec/ex_apprec.c new file mode 100644 index 0000000..c1440c8 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec.c @@ -0,0 +1,278 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include <sys/types.h> +#include <sys/stat.h> + +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "db.h" +#include "db_int.h" +#include "dbinc/db_swap.h" + +#include "ex_apprec.h" + +int apprec_dispatch __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); +int open_env __P((const char *, FILE *, const char *, DB_ENV **)); +int verify_absence __P((DB_ENV *, const char *)); +int verify_presence __P((DB_ENV *, const char *)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + DB_ENV *dbenv; + DB_LSN lsn; + DB_TXN *txn; + DBT dirnamedbt; + int ret; + const char *home; + char ch, dirname[256]; + const char *progname = "ex_apprec"; /* Program name. */ + + /* Default home. */ + home = "TESTDIR"; + + while ((ch = getopt(argc, argv, "h:")) != EOF) + switch (ch) { + case 'h': + home = optarg; + break; + default: + fprintf(stderr, "usage: %s [-h home]", progname); + exit(EXIT_FAILURE); + } + + printf("Set up environment.\n"); + if ((ret = open_env(home, stderr, progname, &dbenv)) != 0) + return (EXIT_FAILURE); + + printf("Create a directory in a transaction.\n"); + /* + * This application's convention is to log the full directory name, + * including trailing nul. + */ + memset(&dirnamedbt, 0, sizeof(dirnamedbt)); + sprintf(dirname, "%s/MYDIRECTORY", home); + dirnamedbt.data = dirname; + dirnamedbt.size = strlen(dirname) + 1; + + if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + return (EXIT_FAILURE); + } + + /* + * Remember, always log actions before you execute them! + * Since this log record is describing a file system operation and + * we have no control over when file system operations go to disk, + * we need to flush the log record immediately to ensure that the + * log record is on disk before the operation it describes. The + * flush would not be necessary were we doing an operation into the + * BDB mpool and using LSNs that mpool knew about. + */ + memset(&lsn, 0, sizeof(lsn)); + if ((ret = + ex_apprec_mkdir_log(dbenv, + txn, &lsn, DB_FLUSH, &dirnamedbt)) != 0) { + dbenv->err(dbenv, ret, "mkdir_log"); + return (EXIT_FAILURE); + } + if (mkdir(dirname, 0755) != 0) { + dbenv->err(dbenv, errno, "mkdir"); + return (EXIT_FAILURE); + } + + printf("Verify the directory's presence: "); + verify_presence(dbenv, dirname); + printf("check.\n"); + + /* Now abort the transaction and verify that the directory goes away. */ + printf("Abort the transaction.\n"); + if ((ret = txn->abort(txn)) != 0) { + dbenv->err(dbenv, ret, "txn_abort"); + return (EXIT_FAILURE); + } + + printf("Verify the directory's absence: "); + verify_absence(dbenv, dirname); + printf("check.\n"); + + /* Now do the same thing over again, only with a commit this time. */ + printf("Create a directory in a transaction.\n"); + memset(&dirnamedbt, 0, sizeof(dirnamedbt)); + sprintf(dirname, "%s/MYDIRECTORY", home); + dirnamedbt.data = dirname; + dirnamedbt.size = strlen(dirname) + 1; + if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_begin"); + return (EXIT_FAILURE); + } + + memset(&lsn, 0, sizeof(lsn)); + if ((ret = + ex_apprec_mkdir_log(dbenv, txn, &lsn, 0, &dirnamedbt)) != 0) { + dbenv->err(dbenv, ret, "mkdir_log"); + return (EXIT_FAILURE); + } + if (mkdir(dirname, 0755) != 0) { + dbenv->err(dbenv, errno, "mkdir"); + return (EXIT_FAILURE); + } + + printf("Verify the directory's presence: "); + verify_presence(dbenv, dirname); + printf("check.\n"); + + /* Now abort the transaction and verify that the directory goes away. */ + printf("Commit the transaction.\n"); + if ((ret = txn->commit(txn, 0)) != 0) { + dbenv->err(dbenv, ret, "txn_commit"); + return (EXIT_FAILURE); + } + + printf("Verify the directory's presence: "); + verify_presence(dbenv, dirname); + printf("check.\n"); + + printf("Now remove the directory, then run recovery.\n"); + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret)); + return (EXIT_FAILURE); + } + if (rmdir(dirname) != 0) { + fprintf(stderr, + "%s: rmdir failed with error %s", progname, + strerror(errno)); + } + verify_absence(dbenv, dirname); + + /* Opening with DB_RECOVER runs recovery. */ + if ((ret = open_env(home, stderr, progname, &dbenv)) != 0) + return (EXIT_FAILURE); + + printf("Verify the directory's presence: "); + verify_presence(dbenv, dirname); + printf("check.\n"); + + /* Close the handle. */ + if ((ret = dbenv->close(dbenv, 0)) != 0) { + fprintf(stderr, "DB_ENV->close: %s\n", db_strerror(ret)); + return (EXIT_FAILURE); + } + + return (EXIT_SUCCESS); +} + +int +open_env(home, errfp, progname, dbenvp) + const char *home, *progname; + FILE *errfp; + DB_ENV **dbenvp; +{ + DB_ENV *dbenv; + int ret; + + /* + * Create an environment object and initialize it for error + * reporting. + */ + if ((ret = db_env_create(&dbenv, 0)) != 0) { + fprintf(errfp, "%s: %s\n", progname, db_strerror(ret)); + return (ret); + } + dbenv->set_errfile(dbenv, errfp); + dbenv->set_errpfx(dbenv, progname); + + /* Set up our custom recovery dispatch function. */ + if ((ret = dbenv->set_app_dispatch(dbenv, apprec_dispatch)) != 0) { + dbenv->err(dbenv, ret, "set_app_dispatch"); + return (ret); + } + + /* + * Open the environment with full transactional support, running + * recovery. + */ + if ((ret = + dbenv->open(dbenv, home, DB_CREATE | DB_RECOVER | DB_INIT_LOCK | + DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN, 0)) != 0) { + dbenv->err(dbenv, ret, "environment open: %s", home); + dbenv->close(dbenv, 0); + return (ret); + } + + *dbenvp = dbenv; + return (0); +} + +/* + * Sample application dispatch function to handle user-specified log record + * types. + */ +int +apprec_dispatch(dbenv, dbt, lsn, op) + DB_ENV *dbenv; + DBT *dbt; + DB_LSN *lsn; + db_recops op; +{ + u_int32_t rectype; + + /* Pull the record type out of the log record. */ + LOGCOPY_32(dbenv->env, &rectype, dbt->data); + + switch (rectype) { + case DB_ex_apprec_mkdir: + return (ex_apprec_mkdir_recover(dbenv, dbt, lsn, op)); + default: + /* + * We've hit an unexpected, allegedly user-defined record + * type. + */ + dbenv->errx(dbenv, "Unexpected log record type encountered"); + return (EINVAL); + } +} + +int +verify_absence(dbenv, dirname) + DB_ENV *dbenv; + const char *dirname; +{ + + if (access(dirname, F_OK) == 0) { + dbenv->errx(dbenv, "Error--directory present!"); + exit(EXIT_FAILURE); + } + + return (0); +} + +int +verify_presence(dbenv, dirname) + DB_ENV *dbenv; + const char *dirname; +{ + + if (access(dirname, F_OK) != 0) { + dbenv->errx(dbenv, "Error--directory not present!"); + exit(EXIT_FAILURE); + } + + return (0); +} diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec.h b/db-4.8.30/examples_c/ex_apprec/ex_apprec.h new file mode 100644 index 0000000..39bdb67 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec.h @@ -0,0 +1,24 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +#ifndef _EX_APPREC_H_ +#define _EX_APPREC_H_ + +#include "ex_apprec_auto.h" + +int ex_apprec_mkdir_log + __P((DB_ENV *, DB_TXN *, DB_LSN *, u_int32_t, const DBT *)); +int ex_apprec_mkdir_print + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); +int ex_apprec_mkdir_read + __P((DB_ENV *, void *, ex_apprec_mkdir_args **)); +int ex_apprec_mkdir_recover + __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); +int ex_apprec_init_print __P((DB_ENV *, DB_DISTAB *)); + +#endif /* !_EX_APPREC_H_ */ diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec.src b/db-4.8.30/examples_c/ex_apprec/ex_apprec.src new file mode 100644 index 0000000..8bdba5d --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec.src @@ -0,0 +1,33 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +PREFIX ex_apprec +INCLUDE #include "ex_apprec.h" + +/* + * This is the source file used to generate the application-specific recovery + * functions used by the ex_apprec example. It should be turned into usable + * source code (including a template for the recovery function itself) by + * invoking changing to the dist directory of the DB distribution and + * running the gen_rec.awk script there as follows: + * + * awk -f ./gen_rec.awk \ + * -v source_file=../examples_c/ex_apprec/ex_apprec_auto.c \ + * -v header_file=../examples_c/ex_apprec/ex_apprec_auto.h \ + * -v template_file=../examples_c/ex_apprec/ex_apprec_template \ + * < ../examples_c/ex_apprec/ex_apprec.src + */ + +/* + * mkdir: used to create a directory + * + * dirname: relative or absolute pathname of the directory to be created + */ +BEGIN mkdir 42 10000 +DBT dirname DBT s +END diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.c b/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.c new file mode 100644 index 0000000..ae5114d --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.c @@ -0,0 +1,140 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#include "db_config.h" +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "db.h" +#include "db_int.h" +#include "dbinc/db_swap.h" +#include "ex_apprec.h" +/* + * PUBLIC: int ex_apprec_mkdir_read __P((DB_ENV *, void *, + * PUBLIC: ex_apprec_mkdir_args **)); + */ +int +ex_apprec_mkdir_read(dbenv, recbuf, argpp) + DB_ENV *dbenv; + void *recbuf; + ex_apprec_mkdir_args **argpp; +{ + ex_apprec_mkdir_args *argp; + u_int8_t *bp; + ENV *env; + + env = dbenv->env; + + if ((argp = malloc(sizeof(ex_apprec_mkdir_args) + sizeof(DB_TXN))) == NULL) + return (ENOMEM); + bp = recbuf; + argp->txnp = (DB_TXN *)&argp[1]; + memset(argp->txnp, 0, sizeof(DB_TXN)); + + LOGCOPY_32(env, &argp->type, bp); + bp += sizeof(argp->type); + + LOGCOPY_32(env, &argp->txnp->txnid, bp); + bp += sizeof(argp->txnp->txnid); + + LOGCOPY_TOLSN(env, &argp->prev_lsn, bp); + bp += sizeof(DB_LSN); + + memset(&argp->dirname, 0, sizeof(argp->dirname)); + LOGCOPY_32(env,&argp->dirname.size, bp); + bp += sizeof(u_int32_t); + argp->dirname.data = bp; + bp += argp->dirname.size; + + *argpp = argp; + return (0); +} + +/* + * PUBLIC: int ex_apprec_mkdir_log __P((DB_ENV *, DB_TXN *, DB_LSN *, + * PUBLIC: u_int32_t, const DBT *)); + */ +int +ex_apprec_mkdir_log(dbenv, txnp, ret_lsnp, flags, + dirname) + DB_ENV *dbenv; + DB_TXN *txnp; + DB_LSN *ret_lsnp; + u_int32_t flags; + const DBT *dirname; +{ + DBT logrec; + DB_LSN *lsnp, null_lsn, *rlsnp; + ENV *env; + u_int32_t zero, rectype, txn_num; + u_int npad; + u_int8_t *bp; + int ret; + + env = dbenv->env; + rlsnp = ret_lsnp; + rectype = DB_ex_apprec_mkdir; + npad = 0; + ret = 0; + + if (txnp == NULL) { + txn_num = 0; + lsnp = &null_lsn; + null_lsn.file = null_lsn.offset = 0; + } else { + /* + * We need to assign begin_lsn while holding region mutex. + * That assignment is done inside the DbEnv->log_put call, + * so pass in the appropriate memory location to be filled + * in by the log_put code. + */ + DB_SET_TXN_LSNP(txnp, &rlsnp, &lsnp); + txn_num = txnp->txnid; + } + + logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) + + sizeof(u_int32_t) + (dirname == NULL ? 0 : dirname->size); + if ((logrec.data = malloc(logrec.size)) == NULL) + return (ENOMEM); + bp = logrec.data; + + if (npad > 0) + memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); + + bp = logrec.data; + + LOGCOPY_32(env, bp, &rectype); + bp += sizeof(rectype); + + LOGCOPY_32(env, bp, &txn_num); + bp += sizeof(txn_num); + + LOGCOPY_FROMLSN(env, bp, lsnp); + bp += sizeof(DB_LSN); + + if (dirname == NULL) { + zero = 0; + LOGCOPY_32(env, bp, &zero); + bp += sizeof(u_int32_t); + } else { + LOGCOPY_32(env, bp, &dirname->size); + bp += sizeof(dirname->size); + memcpy(bp, dirname->data, dirname->size); + bp += dirname->size; + } + + if ((ret = dbenv->log_put(dbenv, rlsnp, (DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnp != NULL) { + *lsnp = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } +#ifdef LOG_DIAGNOSTIC + if (ret != 0) + (void)ex_apprec_mkdir_print(dbenv, + (DBT *)&logrec, ret_lsnp, DB_TXN_PRINT); +#endif + + free(logrec.data); + return (ret); +} + diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.h b/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.h new file mode 100644 index 0000000..a4b4c63 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec_auto.h @@ -0,0 +1,13 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#ifndef ex_apprec_AUTO_H +#define ex_apprec_AUTO_H +#define DB_ex_apprec_mkdir 10000 +typedef struct _ex_apprec_mkdir_args { + u_int32_t type; + DB_TXN *txnp; + DB_LSN prev_lsn; + DBT dirname; +} ex_apprec_mkdir_args; + +#endif diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec_autop.c b/db-4.8.30/examples_c/ex_apprec/ex_apprec_autop.c new file mode 100644 index 0000000..dcd9ce8 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec_autop.c @@ -0,0 +1,65 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#include "db_config.h" + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include "db.h" +#include "ex_apprec.h" +/* + * PUBLIC: int ex_apprec_mkdir_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops)); + */ +int +ex_apprec_mkdir_print(dbenv, dbtp, lsnp, notused2) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; +{ + ex_apprec_mkdir_args *argp; + int ex_apprec_mkdir_read __P((DB_ENV *, void *, ex_apprec_mkdir_args **)); + u_int32_t i; + int ch; + int ret; + + notused2 = DB_TXN_PRINT; + + if ((ret = ex_apprec_mkdir_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]ex_apprec_mkdir%s: rec: %lu txnp %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, (u_long)lsnp->offset, + (argp->type & DB_debug_FLAG) ? "_debug" : "", + (u_long)argp->type, + (u_long)argp->txnp->txnid, + (u_long)argp->prev_lsn.file, (u_long)argp->prev_lsn.offset); + (void)printf("\tdirname: "); + for (i = 0; i < argp->dirname.size; i++) { + ch = ((u_int8_t *)argp->dirname.data)[i]; + printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch); + } + (void)printf("\n"); + (void)printf("\n"); + free(argp); + return (0); +} + +/* + * PUBLIC: int ex_apprec_init_print __P((DB_ENV *, DB_DISTAB *)); + */ +int +ex_apprec_init_print(dbenv, dtabp) + DB_ENV *dbenv; + DB_DISTAB *dtabp; +{ + int __db_add_recovery __P((DB_ENV *, DB_DISTAB *, + int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops), u_int32_t)); + int ret; + + if ((ret = __db_add_recovery(dbenv, dtabp, + ex_apprec_mkdir_print, DB_ex_apprec_mkdir)) != 0) + return (ret); + return (0); +} diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec_rec.c b/db-4.8.30/examples_c/ex_apprec/ex_apprec_rec.c new file mode 100644 index 0000000..338b454 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec_rec.c @@ -0,0 +1,108 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +/* + * This file is based on the template file ex_apprec_template. Note that + * because ex_apprec_mkdir, like most application-specific recovery functions, + * does not make use of DB-private structures, it has actually been simplified + * significantly. + */ + +#include <sys/stat.h> +#include <sys/types.h> +#include <errno.h> +#include <stdlib.h> + +#include <db.h> + +#include "ex_apprec.h" + +/* + * ex_apprec_mkdir_recover -- + * Recovery function for mkdir. + * + * PUBLIC: int ex_apprec_mkdir_recover + * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops)); + */ +int +ex_apprec_mkdir_recover(dbenv, dbtp, lsnp, op) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; +{ + ex_apprec_mkdir_args *argp; + int ret; + + argp = NULL; + +#ifdef DEBUG_RECOVER + ex_apprec_mkdir_print(dbenv, dbtp, lsnp, op); +#endif + if ((ret = ex_apprec_mkdir_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + switch (op) { + case DB_TXN_ABORT: + case DB_TXN_BACKWARD_ROLL: + /* + * If we're aborting, we need to remove the directory if it + * exists. We log the trailing zero in pathnames, so we can + * simply pass the data part of the DBT into rmdir as a string. + * (Note that we don't have any alignment guarantees, but for + * a char * this doesn't matter.) + * + * Ignore all errors other than ENOENT; DB may attempt to undo + * or redo operations without knowing whether they have already + * been done or undone, so we should never assume in a recovery + * function that the task definitely needs doing or undoing. + */ + ret = rmdir(argp->dirname.data); + if (ret != 0 && errno != ENOENT) + dbenv->err(dbenv, ret, "Error in abort of mkdir"); + else + ret = 0; + break; + case DB_TXN_FORWARD_ROLL: + /* + * The forward direction is just the opposite; here, we ignore + * EEXIST, because the directory may already exist. + */ + ret = mkdir(argp->dirname.data, 0755); + if (ret != 0 && errno != EEXIST) + dbenv->err(dbenv, + ret, "Error in roll-forward of mkdir"); + else + ret = 0; + break; + default: + /* + * We might want to handle DB_TXN_PRINT or DB_TXN_APPLY here, + * too, but we don't try to print the log records and aren't + * using replication, so there's no need to in this example. + */ + dbenv->errx(dbenv, "Unexpected operation type\n"); + return (EINVAL); + } + + /* + * The recovery function is responsible for returning the LSN of the + * previous log record in this transaction, so that transaction aborts + * can follow the chain backwards. + * + * (If we'd wanted the LSN of this record earlier, we could have + * read it from lsnp, as well--but because we weren't working with + * pages or other objects that store their LSN and base recovery + * decisions on it, we didn't need to.) + */ + *lsnp = argp->prev_lsn; + +out: if (argp != NULL) + free(argp); + return (ret); +} diff --git a/db-4.8.30/examples_c/ex_apprec/ex_apprec_template b/db-4.8.30/examples_c/ex_apprec/ex_apprec_template new file mode 100644 index 0000000..55182f6 --- /dev/null +++ b/db-4.8.30/examples_c/ex_apprec/ex_apprec_template @@ -0,0 +1,70 @@ +#include "db.h" + +/* + * ex_apprec_mkdir_recover -- + * Recovery function for mkdir. + * + * PUBLIC: int ex_apprec_mkdir_recover + * PUBLIC: __P((dbenv *, DBT *, DB_LSN *, db_recops)); + */ +int +ex_apprec_mkdir_recover(dbenv, dbtp, lsnp, op) + dbenv *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; +{ + ex_apprec_mkdir_args *argp; + int cmp_n, cmp_p, modified, ret; + +#ifdef DEBUG_RECOVER + (void)ex_apprec_mkdir_print(dbenv, dbtp, lsnp, op); +#endif + argp = NULL; + if ((ret = ex_apprec_mkdir_read(dbenv, dbtp->data, &argp)) != 0) + goto out; + + modified = 0; + cmp_n = 0; + cmp_p = 0; + + /* + * The function now needs to calculate cmp_n and cmp_p based + * on whatever is in argp (usually an LSN representing the state + * of an object BEFORE the operation described in this record was + * applied) and whatever other information the function needs, + * e.g., the LSN of the object as it exists now. + * + * cmp_p should be set to 0 if the current state of the object + * is believed to be same as the state of the object BEFORE the + * described operation was applied. For example, if you had an + * LSN in the log record (argp->prevlsn) and a current LSN of the + * object (curlsn), you might want to do: + * + * cmp_p = log_compare(curlsn, argp->prevlsn); + * + * Similarly, cmp_n should be set to 0 if the current state + * of the object reflects the object AFTER this operation has + * been applied. Thus, if you can figure out an object's current + * LSN, yo might set cmp_n as: + * + * cmp_n = log_compare(lsnp, curlsn); + */ + if (cmp_p == 0 && DB_REDO(op)) { + /* Need to redo update described. */ + modified = 1; + } else if (cmp_n == 0 && !DB_REDO(op)) { + /* Need to undo update described. */ + modified = 1; + } + + /* Allow for following LSN pointers through a transaction. */ + *lsnp = argp->prev_lsn; + ret = 0; + +out: if (argp != NULL) + free(argp); + + return (ret); +} + |