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

fop_rec.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2001-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: fop_rec.c,v 12.6 2005/10/12 17:52:16 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_page.h"
00020 #include "dbinc/db_shash.h"
00021 #include "dbinc/fop.h"
00022 #include "dbinc/db_am.h"
00023 #include "dbinc/mp.h"
00024 #include "dbinc/txn.h"
00025 
00026 /*
00027  * The transactional guarantees Berkeley DB provides for file
00028  * system level operations (database physical file create, delete,
00029  * rename) are based on our understanding of current file system
00030  * semantics; a system that does not provide these semantics and
00031  * guarantees could be in danger.
00032  *
00033  * First, as in standard database changes, fsync and fdatasync must
00034  * work: when applied to the log file, the records written into the
00035  * log must be transferred to stable storage.
00036  *
00037  * Second, it must not be possible for the log file to be removed
00038  * without previous file system level operations being flushed to
00039  * stable storage.  Berkeley DB applications write log records
00040  * describing file system operations into the log, then perform the
00041  * file system operation, then commit the enclosing transaction
00042  * (which flushes the log file to stable storage).  Subsequently,
00043  * a database environment checkpoint may make it possible for the
00044  * application to remove the log file containing the record of the
00045  * file system operation.  DB's transactional guarantees for file
00046  * system operations require the log file removal not succeed until
00047  * all previous filesystem operations have been flushed to stable
00048  * storage.  In other words, the flush of the log file, or the
00049  * removal of the log file, must block until all previous
00050  * filesystem operations have been flushed to stable storage.  This
00051  * semantic is not, as far as we know, required by any existing
00052  * standards document, but we have never seen a filesystem where
00053  * it does not apply.
00054  */
00055 
00056 /*
00057  * __fop_create_recover --
00058  *      Recovery function for create.
00059  *
00060  * PUBLIC: int __fop_create_recover
00061  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00062  */
00063 int
00064 __fop_create_recover(dbenv, dbtp, lsnp, op, info)
00065         DB_ENV *dbenv;
00066         DBT *dbtp;
00067         DB_LSN *lsnp;
00068         db_recops op;
00069         void *info;
00070 {
00071         DB_FH *fhp;
00072         __fop_create_args *argp;
00073         char *real_name;
00074         int ret;
00075 
00076         real_name = NULL;
00077         COMPQUIET(info, NULL);
00078         REC_PRINT(__fop_create_print);
00079         REC_NOOP_INTRO(__fop_create_read);
00080 
00081         if ((ret = __db_appname(dbenv, (APPNAME)argp->appname,
00082             (const char *)argp->name.data, 0, NULL, &real_name)) != 0)
00083                 goto out;
00084 
00085         if (DB_UNDO(op))
00086                 (void)__os_unlink(dbenv, real_name);
00087         else if (DB_REDO(op)) {
00088                 if ((ret = __os_open(dbenv, real_name,
00089                     DB_OSO_CREATE | DB_OSO_EXCL, (int)argp->mode, &fhp)) == 0)
00090                         (void)__os_closehandle(dbenv, fhp);
00091                 else
00092                         goto out;
00093         }
00094 
00095         *lsnp = argp->prev_lsn;
00096 
00097 out: if (real_name != NULL)
00098                 __os_free(dbenv, real_name);
00099 
00100         REC_NOOP_CLOSE;
00101 }
00102 
00103 /*
00104  * __fop_remove_recover --
00105  *      Recovery function for remove.
00106  *
00107  * PUBLIC: int __fop_remove_recover
00108  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00109  */
00110 int
00111 __fop_remove_recover(dbenv, dbtp, lsnp, op, info)
00112         DB_ENV *dbenv;
00113         DBT *dbtp;
00114         DB_LSN *lsnp;
00115         db_recops op;
00116         void *info;
00117 {
00118         __fop_remove_args *argp;
00119         char *real_name;
00120         int ret;
00121 
00122         real_name = NULL;
00123         COMPQUIET(info, NULL);
00124         REC_PRINT(__fop_remove_print);
00125         REC_NOOP_INTRO(__fop_remove_read);
00126 
00127         if ((ret = __db_appname(dbenv, (APPNAME)argp->appname,
00128             (const char *)argp->name.data, 0, NULL, &real_name)) != 0)
00129                 goto out;
00130 
00131         /* Its ok if the file is not there. */
00132         if (DB_REDO(op))
00133                 (void)__memp_nameop(dbenv,
00134                     (u_int8_t *)argp->fid.data, NULL, real_name, NULL, 0);
00135 
00136         *lsnp = argp->prev_lsn;
00137 out:    if (real_name != NULL)
00138                 __os_free(dbenv, real_name);
00139         REC_NOOP_CLOSE;
00140 }
00141 
00142 /*
00143  * __fop_write_recover --
00144  *      Recovery function for writechunk.
00145  *
00146  * PUBLIC: int __fop_write_recover
00147  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00148  */
00149 int
00150 __fop_write_recover(dbenv, dbtp, lsnp, op, info)
00151         DB_ENV *dbenv;
00152         DBT *dbtp;
00153         DB_LSN *lsnp;
00154         db_recops op;
00155         void *info;
00156 {
00157         __fop_write_args *argp;
00158         int ret;
00159 
00160         COMPQUIET(info, NULL);
00161         REC_PRINT(__fop_write_print);
00162         REC_NOOP_INTRO(__fop_write_read);
00163 
00164         ret = 0;
00165         if (DB_UNDO(op))
00166                 DB_ASSERT(argp->flag != 0);
00167         else if (DB_REDO(op))
00168                 ret = __fop_write(dbenv,
00169                     argp->txnid, argp->name.data, (APPNAME)argp->appname,
00170                     NULL, argp->pgsize, argp->pageno, argp->offset,
00171                     argp->page.data, argp->page.size, argp->flag, 0);
00172 
00173         if (ret == 0)
00174                 *lsnp = argp->prev_lsn;
00175         REC_NOOP_CLOSE;
00176 }
00177 
00178 /*
00179  * __fop_rename_recover --
00180  *      Recovery function for rename.
00181  *
00182  * PUBLIC: int __fop_rename_recover
00183  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00184  */
00185 int
00186 __fop_rename_recover(dbenv, dbtp, lsnp, op, info)
00187         DB_ENV *dbenv;
00188         DBT *dbtp;
00189         DB_LSN *lsnp;
00190         db_recops op;
00191         void *info;
00192 {
00193         __fop_rename_args *argp;
00194         DB_FH *fhp;
00195         DBMETA *meta;
00196         char *real_new, *real_old, *src;
00197         int ret;
00198         u_int8_t *fileid, mbuf[DBMETASIZE];
00199 
00200         real_new = NULL;
00201         real_old = NULL;
00202         ret = 0;
00203         fhp = NULL;
00204         meta = (DBMETA *)&mbuf[0];
00205 
00206         COMPQUIET(info, NULL);
00207         REC_PRINT(__fop_rename_print);
00208         REC_NOOP_INTRO(__fop_rename_read);
00209         fileid = argp->fileid.data;
00210 
00211         if ((ret = __db_appname(dbenv, (APPNAME)argp->appname,
00212             (const char *)argp->newname.data, 0, NULL, &real_new)) != 0)
00213                 goto out;
00214         if ((ret = __db_appname(dbenv, (APPNAME)argp->appname,
00215             (const char *)argp->oldname.data, 0, NULL, &real_old)) != 0)
00216                 goto out;
00217 
00218         /*
00219          * Verify that we are manipulating the correct file.  We should always
00220          * be OK on an ABORT or an APPLY, but during recovery, we have to
00221          * check.
00222          */
00223         if (op != DB_TXN_ABORT && op != DB_TXN_APPLY) {
00224                 src = DB_UNDO(op) ? real_new : real_old;
00225                 /*
00226                  * Interpret any error as meaning that the file either doesn't
00227                  * exist, doesn't have a meta-data page, or is in some other
00228                  * way, shape or form, incorrect, so that we should not restore
00229                  * it.
00230                  */
00231                 if (__os_open(dbenv, src, 0, 0, &fhp) != 0)
00232                         goto done;
00233                 if (__fop_read_meta(dbenv,
00234                     src, mbuf, DBMETASIZE, fhp, 1, NULL) != 0)
00235                         goto done;
00236                 if (__db_chk_meta(dbenv, NULL, meta, 1) != 0)
00237                         goto done;
00238                 if (memcmp(argp->fileid.data, meta->uid, DB_FILE_ID_LEN) != 0)
00239                         goto done;
00240                 (void)__os_closehandle(dbenv, fhp);
00241                 fhp = NULL;
00242                 if (DB_REDO(op)) {
00243                         /*
00244                          * Check to see if the target file exists.  If it
00245                          * does and it does not have the proper id then
00246                          * it is a later version.  We just remove the source
00247                          * file since the state of the world is beyond this
00248                          * point.
00249                          */
00250                         if (__os_open(dbenv, real_new, 0, 0, &fhp) == 0 &&
00251                             __fop_read_meta(dbenv, src, mbuf,
00252                             DBMETASIZE, fhp, 1, NULL) == 0 &&
00253                             __db_chk_meta(dbenv, NULL, meta, 1) == 0 &&
00254                             memcmp(argp->fileid.data,
00255                             meta->uid, DB_FILE_ID_LEN) != 0) {
00256                                 (void)__memp_nameop(dbenv,
00257                                     fileid, NULL, real_old, NULL, 0);
00258                                 goto done;
00259                         }
00260                 }
00261         }
00262 
00263         if (DB_UNDO(op))
00264                 (void)__memp_nameop(dbenv, fileid,
00265                     (const char *)argp->oldname.data, real_new, real_old, 0);
00266         if (DB_REDO(op))
00267                 (void)__memp_nameop(dbenv, fileid,
00268                     (const char *)argp->newname.data, real_old, real_new, 0);
00269 
00270 done:   *lsnp = argp->prev_lsn;
00271 out:    if (real_new != NULL)
00272                 __os_free(dbenv, real_new);
00273         if (real_old != NULL)
00274                 __os_free(dbenv, real_old);
00275         if (fhp != NULL)
00276                 (void)__os_closehandle(dbenv, fhp);
00277 
00278         REC_NOOP_CLOSE;
00279 }
00280 
00281 /*
00282  * __fop_file_remove_recover --
00283  *      Recovery function for file_remove.  On the REDO pass, we need to
00284  * make sure no one recreated the file while we weren't looking.  On an
00285  * undo pass must check if the file we are interested in is the one that
00286  * exists and then set the status of the child transaction depending on
00287  * what we find out.
00288  *
00289  * PUBLIC: int __fop_file_remove_recover
00290  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00291  */
00292 int
00293 __fop_file_remove_recover(dbenv, dbtp, lsnp, op, info)
00294         DB_ENV *dbenv;
00295         DBT *dbtp;
00296         DB_LSN *lsnp;
00297         db_recops op;
00298         void *info;
00299 {
00300         __fop_file_remove_args *argp;
00301         DBMETA *meta;
00302         DB_FH *fhp;
00303         char *real_name;
00304         int is_real, is_tmp, ret;
00305         size_t len;
00306         u_int8_t mbuf[DBMETASIZE];
00307         u_int32_t cstat, ret_stat;
00308 
00309         fhp = NULL;
00310         is_real = is_tmp = 0;
00311         real_name = NULL;
00312         meta = (DBMETA *)&mbuf[0];
00313         REC_PRINT(__fop_file_remove_print);
00314         REC_NOOP_INTRO(__fop_file_remove_read);
00315 
00316         /*
00317          * This record is only interesting on the backward, forward, and
00318          * apply phases.
00319          */
00320         if (op != DB_TXN_BACKWARD_ROLL &&
00321             op != DB_TXN_FORWARD_ROLL && op != DB_TXN_APPLY)
00322                 goto done;
00323 
00324         if ((ret = __db_appname(dbenv,
00325             (APPNAME)argp->appname, argp->name.data, 0, NULL, &real_name)) != 0)
00326                 goto out;
00327 
00328         /* Verify that we are manipulating the correct file.  */
00329         len = 0;
00330         if (__os_open(dbenv, real_name, 0, 0, &fhp) != 0 ||
00331             (ret = __fop_read_meta(dbenv, real_name,
00332             mbuf, DBMETASIZE, fhp, 1, &len)) != 0) {
00333                 /*
00334                  * If len is non-zero, then the file exists and has something
00335                  * in it, but that something isn't a full meta-data page, so
00336                  * this is very bad.  Bail out!
00337                  */
00338                 if (len != 0)
00339                         goto out;
00340 
00341                 /* File does not exist. */
00342                 cstat = TXN_EXPECTED;
00343         } else {
00344                 /*
00345                  * We can ignore errors here since we'll simply fail the
00346                  * checks below and assume this is the wrong file.
00347                  */
00348                 (void)__db_chk_meta(dbenv, NULL, meta, 1);
00349                 is_real =
00350                     memcmp(argp->real_fid.data, meta->uid, DB_FILE_ID_LEN) == 0;
00351                 is_tmp =
00352                     memcmp(argp->tmp_fid.data, meta->uid, DB_FILE_ID_LEN) == 0;
00353 
00354                 if (!is_real && !is_tmp)
00355                         /* File exists, but isn't what we were removing. */
00356                         cstat = TXN_IGNORE;
00357                 else
00358                         /* File exists and is the one that we were removing. */
00359                         cstat = TXN_COMMIT;
00360         }
00361         if (fhp != NULL) {
00362                 (void)__os_closehandle(dbenv, fhp);
00363                 fhp = NULL;
00364         }
00365 
00366         if (DB_UNDO(op)) {
00367                 /* On the backward pass, we leave a note for the child txn. */
00368                 if ((ret = __db_txnlist_update(dbenv,
00369                     info, argp->child, cstat, NULL, &ret_stat, 1)) != 0)
00370                         goto out;
00371         } else if (DB_REDO(op)) {
00372                 /*
00373                  * On the forward pass, check if someone recreated the
00374                  * file while we weren't looking.
00375                  */
00376                 if (cstat == TXN_COMMIT)
00377                         (void)__memp_nameop(dbenv,
00378                             is_real ? argp->real_fid.data : argp->tmp_fid.data,
00379                             NULL, real_name, NULL, 0);
00380         }
00381 
00382 done:   *lsnp = argp->prev_lsn;
00383         ret = 0;
00384 
00385 out:    if (real_name != NULL)
00386                 __os_free(dbenv, real_name);
00387         if (fhp != NULL)
00388                 (void)__os_closehandle(dbenv, fhp);
00389         REC_NOOP_CLOSE;
00390 }

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