Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
10
examples_c/ex_apprec/auto_rebuild
Normal file
10
examples_c/ex_apprec/auto_rebuild
Normal file
@@ -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
|
||||
277
examples_c/ex_apprec/ex_apprec.c
Normal file
277
examples_c/ex_apprec/ex_apprec.c
Normal file
@@ -0,0 +1,277 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ex_apprec.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#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_config.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);
|
||||
}
|
||||
24
examples_c/ex_apprec/ex_apprec.h
Normal file
24
examples_c/ex_apprec/ex_apprec.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ex_apprec.h 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#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_ */
|
||||
33
examples_c/ex_apprec/ex_apprec.src
Normal file
33
examples_c/ex_apprec/ex_apprec.src
Normal file
@@ -0,0 +1,33 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 2002,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ex_apprec.src,v 12.8 2008/01/08 20:58:24 bostic Exp $
|
||||
*/
|
||||
|
||||
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
|
||||
140
examples_c/ex_apprec/ex_apprec_auto.c
Normal file
140
examples_c/ex_apprec/ex_apprec_auto.c
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
13
examples_c/ex_apprec/ex_apprec_auto.h
Normal file
13
examples_c/ex_apprec/ex_apprec_auto.h
Normal file
@@ -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
|
||||
65
examples_c/ex_apprec/ex_apprec_autop.c
Normal file
65
examples_c/ex_apprec/ex_apprec_autop.c
Normal file
@@ -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);
|
||||
}
|
||||
108
examples_c/ex_apprec/ex_apprec_rec.c
Normal file
108
examples_c/ex_apprec/ex_apprec_rec.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: ex_apprec_rec.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
70
examples_c/ex_apprec/ex_apprec_template
Normal file
70
examples_c/ex_apprec/ex_apprec_template
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user