00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996-2005 00005 * Sleepycat Software. All rights reserved. 00006 * 00007 * $Id: ex_apprec_rec.c,v 12.1 2005/06/16 20:22:06 bostic Exp $ 00008 */ 00009 00010 /* 00011 * This file is based on the template file ex_apprec_template. Note that 00012 * because ex_apprec_mkdir, like most application-specific recovery functions, 00013 * does not make use of DB-private structures, it has actually been simplified 00014 * significantly. 00015 */ 00016 00017 #include <sys/types.h> 00018 #include <sys/stat.h> 00019 #include <errno.h> 00020 #include <stdlib.h> 00021 #include <unistd.h> 00022 00023 #include <db.h> 00024 00025 #include "ex_apprec.h" 00026 00027 /* 00028 * ex_apprec_mkdir_recover -- 00029 * Recovery function for mkdir. 00030 * 00031 * PUBLIC: int ex_apprec_mkdir_recover 00032 * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); 00033 */ 00034 int 00035 ex_apprec_mkdir_recover(dbenv, dbtp, lsnp, op, info) 00036 DB_ENV *dbenv; 00037 DBT *dbtp; 00038 DB_LSN *lsnp; 00039 db_recops op; 00040 void *info; 00041 { 00042 ex_apprec_mkdir_args *argp; 00043 int ret; 00044 00045 argp = NULL; 00046 00047 /* 00048 * Shut up the compiler--"info" is used for the recovery functions 00049 * belonging to transaction meta-operations such as txn_create, and 00050 * need not concern us here either. 00051 */ 00052 info = NULL; 00053 00054 if ((ret = ex_apprec_mkdir_read(dbenv, dbtp->data, &argp)) != 0) 00055 goto out; 00056 00057 switch (op) { 00058 case DB_TXN_ABORT: 00059 case DB_TXN_BACKWARD_ROLL: 00060 /* 00061 * If we're aborting, we need to remove the directory if it 00062 * exists. We log the trailing zero in pathnames, so we can 00063 * simply pass the data part of the DBT into rmdir as a string. 00064 * (Note that we don't have any alignment guarantees, but for 00065 * a char * this doesn't matter.) 00066 * 00067 * Ignore all errors other than ENOENT; DB may attempt to undo 00068 * or redo operations without knowing whether they have already 00069 * been done or undone, so we should never assume in a recovery 00070 * function that the task definitely needs doing or undoing. 00071 */ 00072 ret = rmdir(argp->dirname.data); 00073 if (ret != 0 && errno != ENOENT) 00074 dbenv->err(dbenv, ret, "Error in abort of mkdir"); 00075 else 00076 ret = 0; 00077 break; 00078 case DB_TXN_FORWARD_ROLL: 00079 /* 00080 * The forward direction is just the opposite; here, we ignore 00081 * EEXIST, because the directory may already exist. 00082 */ 00083 ret = mkdir(argp->dirname.data, 0755); 00084 if (ret != 0 && errno != EEXIST) 00085 dbenv->err(dbenv, 00086 ret, "Error in roll-forward of mkdir"); 00087 else 00088 ret = 0; 00089 break; 00090 default: 00091 /* 00092 * We might want to handle DB_TXN_PRINT or DB_TXN_APPLY here, 00093 * too, but we don't try to print the log records and aren't 00094 * using replication, so there's no need to in this example. 00095 */ 00096 dbenv->errx(dbenv, "Unexpected operation type\n"); 00097 return (EINVAL); 00098 } 00099 00100 /* 00101 * The recovery function is responsible for returning the LSN of the 00102 * previous log record in this transaction, so that transaction aborts 00103 * can follow the chain backwards. 00104 * 00105 * (If we'd wanted the LSN of this record earlier, we could have 00106 * read it from lsnp, as well--but because we weren't working with 00107 * pages or other objects that store their LSN and base recovery 00108 * decisions on it, we didn't need to.) 00109 */ 00110 *lsnp = argp->prev_lsn; 00111 00112 out: if (argp != NULL) 00113 free(argp); 00114 return (ret); 00115 }