diff options
Diffstat (limited to 'src/fileops/fop_rec.c')
-rw-r--r-- | src/fileops/fop_rec.c | 759 |
1 files changed, 717 insertions, 42 deletions
diff --git a/src/fileops/fop_rec.c b/src/fileops/fop_rec.c index 52d6175d..71a81ad6 100644 --- a/src/fileops/fop_rec.c +++ b/src/fileops/fop_rec.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -9,16 +9,63 @@ #include "db_config.h" #include "db_int.h" +#include "dbinc/blob.h" #include "dbinc/db_page.h" #include "dbinc/fop.h" #include "dbinc/db_am.h" #include "dbinc/mp.h" #include "dbinc/txn.h" +typedef enum { + DB_APP53_NONE=0, /* No type (region). */ + DB_APP53_DATA, /* Data file. */ + DB_APP53_LOG, /* Log file. */ + DB_APP53_META, /* Persistent metadata file. */ + DB_APP53_RECOVER, /* We are in recovery. */ + DB_APP53_TMP /* Temporary file. */ +} APPNAME53; + +static APPNAME __fop_convert_appname __P((ENV *, APPNAME53)); +static int __fop_create_recover_int __P((ENV *, char *, db_recops, int)); static int __fop_rename_recover_int __P((ENV *, DBT *, DB_LSN *, db_recops, void *, int)); +static int __fop_rename_60_recover_int + __P((ENV *, DBT *, DB_LSN *, db_recops, void *, int)); static int __fop_rename_42_recover_int __P((ENV *, DBT *, DB_LSN *, db_recops, void *, int)); +static int __fop_write_file_recover_int + __P((ENV *, db_recops, + APPNAME, u_int32_t, DBT *, DBT *, DBT *, DBT *, off_t, DB_TXN *)); + +/* + * The APPNAME enumermation was changed in 6.0 to include DB_APP_BLOB. APPNAME + * is used by the log records __fop_create, __fop_write, and __fop_rename. + * __fop_write_file also includes an APPNAME field, but that record was created + * in 6.0. + */ +static APPNAME +__fop_convert_appname(env, appname) + ENV *env; + APPNAME53 appname; +{ + switch(appname) + { + case DB_APP53_NONE: + return (DB_APP_NONE); + case DB_APP53_DATA: + return (DB_APP_DATA); + case DB_APP53_LOG: + return (DB_APP_LOG); + case DB_APP53_META: + return (DB_APP_META); + case DB_APP53_RECOVER: + return (DB_APP_RECOVER); + case DB_APP53_TMP: + return (DB_APP_TMP); + } + DB_ASSERT(env, 0); + return (DB_APP_NONE); +} /* * The transactional guarantees Berkeley DB provides for file @@ -50,6 +97,85 @@ static int __fop_rename_42_recover_int * it does not apply. */ +static int +__fop_create_recover_int(env, real_name, op, mode) + ENV *env; + char *real_name; + db_recops op; + int mode; +{ + DB_FH *fhp; + DBMETA *meta; + u_int8_t mbuf[DBMETASIZE]; + int ret; + char *path; +#ifdef HAVE_REPLICATION + DELAYED_BLOB_LIST *dbl; + int view_partial; + + dbl = NULL; +#endif + meta = (DBMETA *)mbuf; + ret = 0; + + if (DB_UNDO(op)) { + /* + * If the file was opened in mpool, we must mark it as + * dead via nameop which will also unlink the file. + */ + if (__os_open(env, real_name, 0, 0, 0, &fhp) == 0) { + if (__fop_read_meta(env, + real_name, mbuf, DBMETASIZE, fhp, 1, NULL) == 0 && + __db_chk_meta(env, NULL, meta, DB_CHK_META) == 0) { + if ((ret = __memp_nameop(env, + meta->uid, NULL, real_name, NULL, 0)) != 0) + goto out; + } else { + (void)__os_closehandle(env, fhp); + goto do_unlink; + } + (void)__os_closehandle(env, fhp); + } else +do_unlink: (void)__os_unlink(env, real_name, 0); + } else if (DB_REDO(op)) { + path = real_name; +#ifdef DB_WIN32 + /* + * Absolute paths on windows can result in it creating a + * "C" or "D" directory in the working directory. + */ + if (__os_abspath(real_name)) + path += 2; +#endif + +#ifdef HAVE_REPLICATION + /* + * Prevent replication of blob files if their owning database + * is not replicated. + */ + if (IS_VIEW_SITE(env) && IS_BLOB_FILE(path)) { + if ((ret = __rep_call_partial(env, + path, &view_partial, 0, &dbl)) != 0) + goto out; + DB_ASSERT(env, dbl == NULL); + if (view_partial == 0) + goto out; + } +#endif + /* Blob directories might not exist yet. */ + if (__os_exists(env, real_name, NULL) != 0 && + (ret = __db_mkpath(env, path)) != 0) + goto out; + + if ((ret = __os_open(env, real_name, + 0, DB_OSO_CREATE, mode, &fhp)) == 0) + (void)__os_closehandle(env, fhp); + else + goto out; + } +out: return (ret); +} + /* * __fop_create_recover -- * Recovery function for create. @@ -66,9 +192,6 @@ __fop_create_recover(env, dbtp, lsnp, op, info) void *info; { __fop_create_args *argp; - DB_FH *fhp; - DBMETA *meta; - u_int8_t mbuf[DBMETASIZE]; int ret; char *real_name; const char *dirname; @@ -78,7 +201,6 @@ __fop_create_recover(env, dbtp, lsnp, op, info) real_name = NULL; REC_PRINT(__fop_create_print); REC_NOOP_INTRO(__fop_create_read); - meta = (DBMETA *)mbuf; if (argp->dirname.size == 0) dirname = NULL; @@ -90,32 +212,60 @@ __fop_create_recover(env, dbtp, lsnp, op, info) (const char *)argp->name.data, &dirname, &real_name)) != 0) goto out; - if (DB_UNDO(op)) { - /* - * If the file was opened in mpool, we must mark it as - * dead via nameop which will also unlink the file. - */ - if (__os_open(env, real_name, 0, 0, 0, &fhp) == 0) { - if (__fop_read_meta(env, - real_name, mbuf, DBMETASIZE, fhp, 1, NULL) == 0 && - __db_chk_meta(env, NULL, meta, 1) == 0) { - if ((ret = __memp_nameop(env, - meta->uid, NULL, real_name, NULL, 0)) != 0) - goto out; - } else { - (void)__os_closehandle(env, fhp); - goto do_unlink; - } - (void)__os_closehandle(env, fhp); - } else -do_unlink: (void)__os_unlink(env, real_name, 0); - } else if (DB_REDO(op)) { - if ((ret = __os_open(env, real_name, 0, - DB_OSO_CREATE, (int)argp->mode, &fhp)) == 0) - (void)__os_closehandle(env, fhp); - else - goto out; - } + if ((ret = __fop_create_recover_int( + env, real_name, op, (int)argp->mode)) != 0) + goto out; + + *lsnp = argp->prev_lsn; + +out: if (real_name != NULL) + __os_free(env, real_name); + + REC_NOOP_CLOSE; +} + +/* + * __fop_create_60_recover -- + * Recovery function for create. + * + * PUBLIC: int __fop_create_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_create_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_create_60_args *argp; + APPNAME appname; + int ret; + char *real_name; + const char *dirname; + + COMPQUIET(info, NULL); + + real_name = NULL; + REC_PRINT(__fop_create_60_print); + REC_NOOP_INTRO(__fop_create_60_read); + + if (argp->dirname.size == 0) + dirname = NULL; + else + dirname = (const char *)argp->dirname.data; + + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + + if ((ret = __db_appname(env, + appname == DB_APP_DATA ? DB_APP_RECOVER : appname, + (const char *)argp->name.data, &dirname, &real_name)) != 0) + goto out; + + if ((ret = __fop_create_recover_int( + env, real_name, op, (int)argp->mode)) != 0) + goto out; *lsnp = argp->prev_lsn; @@ -144,6 +294,7 @@ __fop_create_42_recover(env, dbtp, lsnp, op, info) DB_FH *fhp; DBMETA *meta; u_int8_t mbuf[DBMETASIZE]; + APPNAME appname; int ret; char *real_name; @@ -153,8 +304,9 @@ __fop_create_42_recover(env, dbtp, lsnp, op, info) REC_PRINT(__fop_create_print); REC_NOOP_INTRO(__fop_create_read); meta = (DBMETA *)mbuf; + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); - if ((ret = __db_appname(env, (APPNAME)argp->appname, + if ((ret = __db_appname(env, appname, (const char *)argp->name.data, NULL, &real_name)) != 0) goto out; @@ -166,7 +318,7 @@ __fop_create_42_recover(env, dbtp, lsnp, op, info) if (__os_open(env, real_name, 0, 0, 0, &fhp) == 0) { if (__fop_read_meta(env, real_name, mbuf, DBMETASIZE, fhp, 1, NULL) == 0 && - __db_chk_meta(env, NULL, meta, 1) == 0) { + __db_chk_meta(env, NULL, meta, DB_CHK_META) == 0) { if ((ret = __memp_nameop(env, meta->uid, NULL, real_name, NULL, 0)) != 0) goto out; @@ -232,6 +384,49 @@ out: if (real_name != NULL) } /* + * __fop_remove_60_recover -- + * Recovery function for remove. + * + * PUBLIC: int __fop_remove_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_remove_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_remove_60_args *argp; + APPNAME appname; + int ret; + char *real_name; + + COMPQUIET(info, NULL); + + real_name = NULL; + REC_PRINT(__fop_remove_60_print); + REC_NOOP_INTRO(__fop_remove_60_read); + + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + + if ((ret = __db_appname(env, appname, + (const char *)argp->name.data, NULL, &real_name)) != 0) + goto out; + + /* Its ok if the file is not there. */ + if (DB_REDO(op)) + (void)__memp_nameop(env, + (u_int8_t *)argp->fid.data, NULL, real_name, NULL, 0); + + *lsnp = argp->prev_lsn; +out: if (real_name != NULL) + __os_free(env, real_name); + REC_NOOP_CLOSE; +} + +/* * __fop_write_recover -- * Recovery function for writechunk. * @@ -251,6 +446,15 @@ __fop_write_recover(env, dbtp, lsnp, op, info) COMPQUIET(info, NULL); +#ifndef HAVE_64BIT_TYPES + COMPQUIET(dbtp, NULL); + COMPQUIET(lsnp, NULL); + COMPQUIET(op, 0); + __db_errx(env, DB_STR("0243", + "Blobs require 64 integer compiler support.")); + return (DB_OPNOTSUP); +#endif + REC_PRINT(__fop_write_print); REC_NOOP_INTRO(__fop_write_read); @@ -272,6 +476,48 @@ __fop_write_recover(env, dbtp, lsnp, op, info) } /* + * __fop_write_60_recover -- + * Recovery function for writechunk. + * + * PUBLIC: int __fop_write_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_write_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_write_60_args *argp; + APPNAME appname; + int ret; + + COMPQUIET(info, NULL); + + REC_PRINT(__fop_write_60_print); + REC_NOOP_INTRO(__fop_write_60_read); + + ret = 0; + if (DB_UNDO(op)) + DB_ASSERT(env, argp->flag != 0); + else if (DB_REDO(op)) { + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + ret = __fop_write(env, + argp->txnp, argp->name.data, + argp->dirname.size == 0 ? NULL : argp->dirname.data, + appname == DB_APP_DATA ? DB_APP_RECOVER : appname, + NULL, argp->pgsize, argp->pageno, argp->offset, + argp->page.data, argp->page.size, argp->flag, 0); + } + + if (ret == 0) + *lsnp = argp->prev_lsn; + REC_NOOP_CLOSE; +} + +/* * __fop_write_42_recover -- * Recovery function for writechunk. * @@ -287,6 +533,7 @@ __fop_write_42_recover(env, dbtp, lsnp, op, info) void *info; { __fop_write_args *argp; + APPNAME appname; int ret; COMPQUIET(info, NULL); @@ -297,18 +544,194 @@ __fop_write_42_recover(env, dbtp, lsnp, op, info) ret = 0; if (DB_UNDO(op)) DB_ASSERT(env, argp->flag != 0); - else if (DB_REDO(op)) + else if (DB_REDO(op)) { + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); ret = __fop_write(env, - argp->txnp, argp->name.data, NULL, (APPNAME)argp->appname, + argp->txnp, argp->name.data, NULL, appname, NULL, argp->pgsize, argp->pageno, argp->offset, argp->page.data, argp->page.size, argp->flag, 0); + } + + if (ret == 0) + *lsnp = argp->prev_lsn; + REC_NOOP_CLOSE; +} + +static int +__fop_write_file_recover_int( + env, op, appname, flag, dirname, name, new_data, old_data, offset, txn) + ENV *env; + db_recops op; + APPNAME appname; + u_int32_t flag; + DBT *dirname; + DBT *name; + DBT *new_data; + DBT *old_data; + off_t offset; + DB_TXN *txn; +{ + DB_FH *fhp; + int ret; + size_t nbytes; + char *path; + + fhp = NULL; + path = NULL; + ret = 0; + + if (DB_UNDO(op)) { + if (flag & DB_FOP_CREATE) { + /* + * File was created in this transaction. Do nothing, + * destroying the file will undo the write. + */ + } else { + if ((ret = __db_appname(env, + appname == DB_APP_DATA ? DB_APP_RECOVER : + appname, name->data, NULL, &path)) != 0) + goto end; + + if (__os_open(env, path, 0, 0, DB_MODE_600, &fhp) != 0) + goto end; + + if (flag & DB_FOP_APPEND) { + /* + * Appended to the end of the file, undo by + * truncating the file. + */ + (void)__os_truncate(env, fhp, 0, 0, offset); + } else { + /* + * Data overwritten in the middle of the file, + * undo by writing back in the old data. + */ + + /* Seek to offset. */ + if ((__os_seek(env, fhp, 0, 0, offset)) != 0) + goto end; + + /* Now do the write. */ + ret = __os_write(env, fhp, + old_data->data, old_data->size, &nbytes); + } + } + } else if (DB_REDO(op)) { + /* + * Not all operations log enough data to be redone. Since + * files are flushed before the transaction commit this is + * not an issue, unless we are on an HA client or initializing + * from a backup. + */ + if (flag & DB_FOP_REDO) { + ret = __fop_write_file(env, txn, name->data, + dirname->size == 0 ? NULL : dirname->data, + appname == DB_APP_DATA ? DB_APP_RECOVER : appname, + NULL, offset, new_data->data, new_data->size, 0); +#ifdef HAVE_REPLICATION + /* + * Blob files of databases that are not replicated are + * also not replicated. So assume any ENOENT errors + * are because the file was not replicated. + */ + if (ret == ENOENT && IS_VIEW_SITE(env)) + ret = 0; +#endif + } else { + /* DB_ASSERT(env, !IS_REP_CLIENT(env)); */ + } + } + +end: if (path != NULL) + __os_free(env, path); + if (fhp != NULL) + (void)__os_closehandle(env, fhp); + return (ret); +} +/* + * __fop_write_file_recover -- + * Recovery function for writing to a blob file. Files are flushed before + * the transaction is committed, so often the file operations do not need + * to be redone or undone. However, since no lsn is stored in the file, + * we always try to redo or undo the operation, since it will not change + * the final state of the file if the operation is not needed. This also + * means that this function has to be very tolerant of errors, such as + * trying to open a file that was deleted, or truncate a file that is + * already short. + * + * PUBLIC: int __fop_write_file_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_write_file_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_write_file_args *argp; + int ret; + COMPQUIET(info, NULL); + +#ifndef HAVE_64BIT_TYPES + COMPQUIET(dbtp, NULL); + COMPQUIET(lsnp, NULL); + COMPQUIET(op, 0); + __db_errx(env, DB_STR("0244", + "Blobs require 64 integer compiler support.")); + return (DB_OPNOTSUP); +#endif + + REC_PRINT(__fop_write_file_print); + REC_NOOP_INTRO(__fop_write_file_read); + + ret = __fop_write_file_recover_int(env, op, + (APPNAME)argp->appname, argp->flag, &argp->dirname, &argp->name, + &argp->new_data, &argp->old_data, (off_t)argp->offset, argp->txnp); if (ret == 0) *lsnp = argp->prev_lsn; REC_NOOP_CLOSE; } /* + * __fop_write_file_60_recover -- + * + * PUBLIC: int __fop_write_file_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_write_file_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_write_file_60_args *argp; + off_t offset; + int ret; + COMPQUIET(info, NULL); + + REC_PRINT(__fop_write_file_60_print); + REC_NOOP_INTRO(__fop_write_file_60_read); + + /* The offset is stored as two u_in32_t values. */ + GET_LO_HI(env, argp->offset_lo, argp->offset_hi, offset, ret); + if (ret != 0) + goto end; + + ret = __fop_write_file_recover_int(env, op, + (APPNAME)argp->appname, argp->flag, &argp->dirname, &argp->name, + &argp->new_data, &argp->old_data, offset, argp->txnp); + +end: if (ret == 0) + *lsnp = argp->prev_lsn; + REC_NOOP_CLOSE; +} + +/* * __fop_rename_recover -- * Recovery functions for rename. There are two variants that * both use the same utility function. Had we known about this on day @@ -408,7 +831,148 @@ __fop_rename_recover_int(env, dbtp, lsnp, op, info, undo) if (__fop_read_meta(env, src, mbuf, DBMETASIZE, fhp, 1, NULL) != 0) goto done; - if (__db_chk_meta(env, NULL, meta, 1) != 0) + if (__db_chk_meta(env, NULL, meta, DB_CHK_META) != 0) + goto done; + if (memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0) + goto done; + (void)__os_closehandle(env, fhp); + fhp = NULL; + if (DB_REDO(op)) { + /* + * Check to see if the target file exists. If it + * does and it does not have the proper id then + * it is a later version. We just remove the source + * file since the state of the world is beyond this + * point. + */ + if (__os_open(env, real_new, 0, 0, 0, &fhp) == 0 && + __fop_read_meta(env, src, mbuf, + DBMETASIZE, fhp, 1, NULL) == 0 && + __db_chk_meta(env, NULL, meta, DB_CHK_META) == 0 && + memcmp(argp->fileid.data, + meta->uid, DB_FILE_ID_LEN) != 0) { + (void)__memp_nameop(env, + fileid, NULL, real_old, NULL, 0); + goto done; + } + } + } + + if (undo && DB_UNDO(op)) + (void)__memp_nameop(env, fileid, + (const char *)argp->oldname.data, real_new, real_old, 0); + if (DB_REDO(op)) + (void)__memp_nameop(env, fileid, + (const char *)argp->newname.data, real_old, real_new, 0); + +done: *lsnp = argp->prev_lsn; +out: if (real_new != NULL) + __os_free(env, real_new); + if (real_old != NULL) + __os_free(env, real_old); + if (fhp != NULL) + (void)__os_closehandle(env, fhp); + + REC_NOOP_CLOSE; +} + +/* + * __fop_rename_60_recover -- + * + * PUBLIC: int __fop_rename_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + * + * PUBLIC: int __fop_rename_noundo_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ + +int +__fop_rename_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + return (__fop_rename_60_recover_int(env, dbtp, lsnp, op, info, 1)); +} + +int +__fop_rename_noundo_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + return (__fop_rename_60_recover_int(env, dbtp, lsnp, op, info, 0)); +} + +static int +__fop_rename_60_recover_int(env, dbtp, lsnp, op, info, undo) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; + int undo; +{ + __fop_rename_60_args *argp; + APPNAME appname; + DB_FH *fhp; + DBMETA *meta; + u_int8_t *fileid, mbuf[DBMETASIZE]; + int ret; + char *real_new, *real_old, *src; + const char *dirname; + + COMPQUIET(info, NULL); + + fhp = NULL; + meta = (DBMETA *)&mbuf[0]; + ret = 0; + real_new = real_old = NULL; + + REC_PRINT(__fop_rename_60_print); + REC_NOOP_INTRO(__fop_rename_60_read); + fileid = argp->fileid.data; + + if (argp->dirname.size == 0) + dirname = NULL; + else + dirname = (const char *)argp->dirname.data; + + + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + if (appname == DB_APP_DATA) + appname = DB_APP_RECOVER; + + if ((ret = __db_appname(env, appname, (const char *)argp->newname.data, + &dirname, &real_new)) != 0) + goto out; + if ((ret = __db_appname(env, appname, (const char *)argp->oldname.data, + &dirname, &real_old)) != 0) + goto out; + + /* + * Verify that we are manipulating the correct file. We should always + * be OK on an ABORT or an APPLY, but during recovery, we have to + * check. + */ + if (op != DB_TXN_ABORT && op != DB_TXN_APPLY) { + src = DB_UNDO(op) ? real_new : real_old; + /* + * Interpret any error as meaning that the file either doesn't + * exist, doesn't have a meta-data page, or is in some other + * way, shape or form, incorrect, so that we should not restore + * it. + */ + if (__os_open(env, src, 0, 0, 0, &fhp) != 0) + goto done; + if (__fop_read_meta(env, + src, mbuf, DBMETASIZE, fhp, 1, NULL) != 0) + goto done; + if (__db_chk_meta(env, NULL, meta, DB_CHK_META) != 0) goto done; if (memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0) goto done; @@ -425,7 +989,7 @@ __fop_rename_recover_int(env, dbtp, lsnp, op, info, undo) if (__os_open(env, real_new, 0, 0, 0, &fhp) == 0 && __fop_read_meta(env, src, mbuf, DBMETASIZE, fhp, 1, NULL) == 0 && - __db_chk_meta(env, NULL, meta, 1) == 0 && + __db_chk_meta(env, NULL, meta, DB_CHK_META) == 0 && memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0) { (void)__memp_nameop(env, @@ -501,6 +1065,7 @@ __fop_rename_42_recover_int(env, dbtp, lsnp, op, info, undo) DB_FH *fhp; DBMETA *meta; u_int8_t *fileid, mbuf[DBMETASIZE]; + APPNAME appname; int ret; char *real_new, *real_old, *src; @@ -515,10 +1080,11 @@ __fop_rename_42_recover_int(env, dbtp, lsnp, op, info, undo) REC_NOOP_INTRO(__fop_rename_read); fileid = argp->fileid.data; - if ((ret = __db_appname(env, (APPNAME)argp->appname, + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + if ((ret = __db_appname(env, appname, (const char *)argp->newname.data, NULL, &real_new)) != 0) goto out; - if ((ret = __db_appname(env, (APPNAME)argp->appname, + if ((ret = __db_appname(env, appname, (const char *)argp->oldname.data, NULL, &real_old)) != 0) goto out; @@ -540,7 +1106,7 @@ __fop_rename_42_recover_int(env, dbtp, lsnp, op, info, undo) if (__fop_read_meta(env, src, mbuf, DBMETASIZE, fhp, 1, NULL) != 0) goto done; - if (__db_chk_meta(env, NULL, meta, 1) != 0) + if (__db_chk_meta(env, NULL, meta, DB_CHK_META) != 0) goto done; if (memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0) goto done; @@ -557,7 +1123,7 @@ __fop_rename_42_recover_int(env, dbtp, lsnp, op, info, undo) if (__os_open(env, real_new, 0, 0, 0, &fhp) == 0 && __fop_read_meta(env, src, mbuf, DBMETASIZE, fhp, 1, NULL) == 0 && - __db_chk_meta(env, NULL, meta, 1) == 0 && + __db_chk_meta(env, NULL, meta, DB_CHK_META) == 0 && memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0) { (void)__memp_nameop(env, @@ -652,7 +1218,115 @@ __fop_file_remove_recover(env, dbtp, lsnp, op, info) * We can ignore errors here since we'll simply fail the * checks below and assume this is the wrong file. */ - (void)__db_chk_meta(env, NULL, meta, 1); + (void)__db_chk_meta(env, NULL, meta, DB_CHK_META); + is_real = + memcmp(argp->real_fid.data, meta->uid, DB_FILE_ID_LEN) == 0; + is_tmp = + memcmp(argp->tmp_fid.data, meta->uid, DB_FILE_ID_LEN) == 0; + + if (!is_real && !is_tmp) + /* File exists, but isn't what we were removing. */ + cstat = TXN_IGNORE; + else + /* File exists and is the one that we were removing. */ + cstat = TXN_COMMIT; + } + if (fhp != NULL) { + (void)__os_closehandle(env, fhp); + fhp = NULL; + } + + if (DB_UNDO(op)) { + /* On the backward pass, we leave a note for the child txn. */ + if ((ret = __db_txnlist_update(env, + info, argp->child, cstat, NULL, &ret_stat, 1)) != 0) + goto out; + } else if (DB_REDO(op)) { + /* + * On the forward pass, check if someone recreated the + * file while we weren't looking. + */ + if (cstat == TXN_COMMIT) + (void)__memp_nameop(env, + is_real ? argp->real_fid.data : argp->tmp_fid.data, + NULL, real_name, NULL, 0); + } + +done: *lsnp = argp->prev_lsn; + ret = 0; + +out: if (real_name != NULL) + __os_free(env, real_name); + if (fhp != NULL) + (void)__os_closehandle(env, fhp); + REC_NOOP_CLOSE; +} + +/* + * __fop_file_remove_60_recover -- + * + * PUBLIC: int __fop_file_remove_60_recover + * PUBLIC: __P((ENV *, DBT *, DB_LSN *, db_recops, void *)); + */ +int +__fop_file_remove_60_recover(env, dbtp, lsnp, op, info) + ENV *env; + DBT *dbtp; + DB_LSN *lsnp; + db_recops op; + void *info; +{ + __fop_file_remove_60_args *argp; + DBMETA *meta; + DB_FH *fhp; + size_t len; + u_int8_t mbuf[DBMETASIZE]; + u_int32_t cstat, ret_stat; + APPNAME appname; + int is_real, is_tmp, ret; + char *real_name; + + fhp = NULL; + meta = (DBMETA *)&mbuf[0]; + is_real = is_tmp = 0; + real_name = NULL; + REC_PRINT(__fop_file_remove_60_print); + REC_NOOP_INTRO(__fop_file_remove_60_read); + + /* + * This record is only interesting on the backward, forward, and + * apply phases. + */ + if (op != DB_TXN_BACKWARD_ROLL && + op != DB_TXN_FORWARD_ROLL && op != DB_TXN_APPLY) + goto done; + + appname = __fop_convert_appname(env, (APPNAME53)argp->appname); + if ((ret = __db_appname(env, appname, + argp->name.data, NULL, &real_name)) != 0) + goto out; + + /* Verify that we are manipulating the correct file. */ + len = 0; + if (__os_open(env, real_name, 0, 0, 0, &fhp) != 0 || + (ret = __fop_read_meta(env, real_name, + mbuf, DBMETASIZE, fhp, 1, &len)) != 0) { + /* + * If len is non-zero, then the file exists and has something + * in it, but that something isn't a full meta-data page, so + * this is very bad. Bail out! + */ + if (len != 0) + goto out; + + /* File does not exist. */ + cstat = TXN_EXPECTED; + } else { + /* + * We can ignore errors here since we'll simply fail the + * checks below and assume this is the wrong file. + */ + (void)__db_chk_meta(env, NULL, meta, DB_CHK_META); is_real = memcmp(argp->real_fid.data, meta->uid, DB_FILE_ID_LEN) == 0; is_tmp = @@ -695,3 +1369,4 @@ out: if (real_name != NULL) (void)__os_closehandle(env, fhp); REC_NOOP_CLOSE; } + |