crdel_rec.c

Go to the documentation of this file.
00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996, 1997, 1998, 1999, 2000
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 
00008 #include "config.h"
00009 
00010 #ifndef lint
00011 static const char revid[] = "$Id: crdel__rec_8c-source.html,v 1.1 2008/06/08 10:16:30 sebdiaz Exp $";
00012 #endif /* not lint */
00013 
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016 
00017 #include <errno.h>
00018 #include <string.h>
00019 #endif
00020 
00021 #include "db_int.h"
00022 #include "db_page.h"
00023 #include "log.h"
00024 #include "hash.h"
00025 #include "mp.h"
00026 #include "db_dispatch.h"
00027 
00028 /*
00029  * CDB___crdel_fileopen_recover --
00030  *      Recovery function for fileopen.
00031  *
00032  * PUBLIC: int CDB___crdel_fileopen_recover
00033  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00034  */
00035 int
00036 CDB___crdel_fileopen_recover(dbenv, dbtp, lsnp, op, info)
00037         DB_ENV *dbenv;
00038         DBT *dbtp;
00039         DB_LSN *lsnp;
00040         db_recops op;
00041         void *info;
00042 {
00043         __crdel_fileopen_args *argp;
00044         DBMETA ondisk;
00045         DB_FH fh;
00046         size_t nr;
00047         int do_unlink, ret;
00048         u_int32_t b, mb, io;
00049         char *real_name;
00050 
00051         COMPQUIET(info, NULL);
00052 
00053         real_name = NULL;
00054         REC_PRINT(CDB___crdel_fileopen_print);
00055 
00056         if ((ret = CDB___crdel_fileopen_read(dbenv, dbtp->data, &argp)) != 0)
00057                 goto out;
00058         /*
00059          * If this is an in-memory database, then the name is going to
00060          * be NULL, which looks like a 0-length name in recovery.
00061          */
00062         if (argp->name.size == 0)
00063                 goto done;
00064 
00065         if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00066             NULL, argp->name.data, 0, NULL, &real_name)) != 0)
00067                 goto out;
00068         if (DB_REDO(op)) {
00069                 /*
00070                  * The create commited, so we need to make sure that the file
00071                  * exists.  A simple open should suffice.
00072                  */
00073                 if ((ret = CDB___os_open(dbenv, real_name,
00074                     DB_OSO_CREATE, argp->mode, &fh)) != 0)
00075                         goto out;
00076                 if ((ret = CDB___os_closehandle(&fh)) != 0)
00077                         goto out;
00078         } else if (DB_UNDO(op)) {
00079                 /*
00080                  * If the file is 0-length then it was in the process of being
00081                  * created, so we should unlink it.  If it is non-0 length, then
00082                  * either someone else created it and we need to leave it
00083                  * untouched or we were in the process of creating it, allocated
00084                  * the first page on a system that requires you to actually
00085                  * write pages as you allocate them, but never got any data
00086                  * on it.
00087                  * If the file doesn't exist, we never got around to creating
00088                  * it, so that's fine.
00089                  */
00090                 if (CDB___os_exists(real_name, NULL) != 0)
00091                         goto done;
00092 
00093                 if ((ret = CDB___os_open(dbenv, real_name, 0, 0, &fh)) != 0)
00094                         goto out;
00095                 if ((ret = CDB___os_ioinfo(dbenv,
00096                     real_name, &fh, &mb, &b, &io)) != 0)
00097                         goto out;
00098                 do_unlink = 0;
00099                 if (mb != 0 || b != 0) {
00100                         /*
00101                          * We need to read the first page
00102                          * to see if its got valid data on it.
00103                          */
00104                         if ((ret = CDB___os_read(dbenv, &fh,
00105                             &ondisk, sizeof(ondisk), &nr)) != 0 ||
00106                             nr != sizeof(ondisk))
00107                                 goto out;
00108                         if (ondisk.magic == 0)
00109                                 do_unlink = 1;
00110                 }
00111                 if ((ret = CDB___os_closehandle(&fh)) != 0)
00112                         goto out;
00113                 /* Check for 0-length and if it is, delete it. */
00114                 if (do_unlink || (mb == 0 && b == 0))
00115                         if ((ret = CDB___os_unlink(dbenv, real_name)) != 0)
00116                                 goto out;
00117         }
00118 
00119 done:   *lsnp = argp->prev_lsn;
00120         ret = 0;
00121 
00122 out:    if (argp != NULL)
00123                 CDB___os_free(argp, sizeof(*argp));
00124         if (real_name != NULL)
00125                 CDB___os_freestr(real_name);
00126         return (ret);
00127 }
00128 
00129 /*
00130  * CDB___crdel_metasub_recover --
00131  *      Recovery function for metasub.
00132  *
00133  * PUBLIC: int CDB___crdel_metasub_recover
00134  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00135  */
00136 int
00137 CDB___crdel_metasub_recover(dbenv, dbtp, lsnp, op, info)
00138         DB_ENV *dbenv;
00139         DBT *dbtp;
00140         DB_LSN *lsnp;
00141         db_recops op;
00142         void *info;
00143 {
00144         __crdel_metasub_args *argp;
00145         DB *file_dbp;
00146         DBC *dbc;
00147         DB_MPOOLFILE *mpf;
00148         PAGE *pagep;
00149         int cmp_p, modified, ret;
00150 
00151         COMPQUIET(info, NULL);
00152         REC_PRINT(CDB___crdel_metasub_print);
00153         REC_INTRO(CDB___crdel_metasub_read, 0);
00154 
00155         if ((ret = CDB_memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
00156                 if (DB_REDO(op)) {
00157                         if ((ret = CDB_memp_fget(mpf,
00158                             &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
00159                                 goto out;
00160                 } else {
00161                         *lsnp = argp->prev_lsn;
00162                         ret = 0;
00163                         goto out;
00164                 }
00165         }
00166 
00167         modified = 0;
00168         cmp_p = CDB_log_compare(&LSN(pagep), &argp->lsn);
00169         CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
00170 
00171         if (cmp_p == 0 && DB_REDO(op)) {
00172                 memcpy(pagep, argp->page.data, argp->page.size);
00173                 LSN(pagep) = *lsnp;
00174                 modified = 1;
00175         } else if (DB_UNDO(op)) {
00176                 /*
00177                  * We want to undo this page creation.  The page creation
00178                  * happened in two parts.  First, we called __bam_new which
00179                  * was logged separately. Then we wrote the meta-data onto
00180                  * the page.  So long as we restore the LSN, then the recovery
00181                  * for __bam_new will do everything else.
00182                  * Don't bother checking the lsn on the page.  If we
00183                  * are rolling back the next thing is that this page
00184                  * will get freed.  Opening the subdb will have reinitialized
00185                  * the page, but not the lsn.
00186                  */
00187                 LSN(pagep) = argp->lsn;
00188                 modified = 1;
00189         }
00190         if ((ret = CDB_memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
00191                 goto out;
00192 
00193 done:   *lsnp = argp->prev_lsn;
00194         ret = 0;
00195 
00196 out:    REC_CLOSE;
00197 }
00198 
00199 /*
00200  * CDB___crdel_metapage_recover --
00201  *      Recovery function for metapage.
00202  *
00203  * PUBLIC: int CDB___crdel_metapage_recover
00204  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00205  */
00206 int
00207 CDB___crdel_metapage_recover(dbenv, dbtp, lsnp, op, info)
00208         DB_ENV *dbenv;
00209         DBT *dbtp;
00210         DB_LSN *lsnp;
00211         db_recops op;
00212         void *info;
00213 {
00214         __crdel_metapage_args *argp;
00215         DB *dbp;
00216         DBMETA *meta, ondisk;
00217         DB_FH fh;
00218         size_t nr;
00219         u_int32_t b, io, mb, pagesize;
00220         int is_done, ret;
00221         char *real_name;
00222 
00223         COMPQUIET(info, NULL);
00224 
00225         real_name = NULL;
00226         memset(&fh, 0, sizeof(fh));
00227         REC_PRINT(CDB___crdel_metapage_print);
00228 
00229         if ((ret = CDB___crdel_metapage_read(dbenv, dbtp->data, &argp)) != 0)
00230                 goto out;
00231 
00232         /*
00233          * If this is an in-memory database, then the name is going to
00234          * be NULL, which looks like a 0-length name in recovery.
00235          */
00236         if (argp->name.size == 0)
00237                 goto done;
00238 
00239         meta = (DBMETA *)argp->page.data;
00240         CDB___ua_memcpy(&pagesize, &meta->pagesize, sizeof(pagesize));
00241 
00242         if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00243             NULL, argp->name.data, 0, NULL, &real_name)) != 0)
00244                 goto out;
00245         if (DB_REDO(op)) {
00246                 if ((ret = CDB___db_fileid_to_db(dbenv,
00247                     &dbp, argp->fileid, 0)) != 0) {
00248                         if (ret == DB_DELETED)
00249                                 goto done;
00250                         else
00251                                 goto out;
00252                 }
00253 
00254                 /*
00255                  * We simply read the first page and if the LSN is 0, we
00256                  * write the meta-data page.
00257                  */
00258                 if ((ret = CDB___os_open(dbenv, real_name, 0, 0, &fh)) != 0)
00259                         goto out;
00260                 if ((ret = CDB___os_seek(dbenv, &fh,
00261                     pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
00262                         goto out;
00263                 /*
00264                  * If the read succeeds then the page exists, then we need
00265                  * to vrify that the page has actually been written, because
00266                  * on some systems (e.g., Windows) we preallocate pages because
00267                  * files aren't allowed to have holes in them.  If the page
00268                  * looks good then we're done.
00269                  */
00270                 if ((ret = CDB___os_read(dbenv, &fh, &ondisk,
00271                     sizeof(ondisk), &nr)) == 0 && nr == sizeof(ondisk)) {
00272                         if (ondisk.magic != 0)
00273                                 goto done;
00274                         if ((ret = CDB___os_seek(dbenv, &fh,
00275                             pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
00276                                 goto out;
00277                 }
00278 
00279                 /*
00280                  * Page didn't exist, update the LSN and write a new one.
00281                  * (seek pointer shouldn't have moved)
00282                  */
00283                 CDB___ua_memcpy(&meta->lsn, lsnp, sizeof(DB_LSN));
00284                 if ((ret = CDB___os_write(dbp->dbenv, &fh,
00285                     argp->page.data, argp->page.size, &nr)) != 0)
00286                         goto out;
00287                 if (nr != (size_t)argp->page.size) {
00288                         CDB___db_err(dbenv, "Write failed during recovery");
00289                         ret = EIO;
00290                         goto out;
00291                 }
00292 
00293                 /*
00294                  * We must close and reopen the file to be sure
00295                  * that we have the proper meta information
00296                  * in the in memory structures
00297                  */
00298 
00299                 if ((ret = CDB___log_reopen_file(dbenv,
00300                      argp->name.data, argp->fileid,
00301                      meta->uid, argp->pgno)) != 0)
00302                         goto out;
00303 
00304                 /* Handle will be closed on exit. */
00305         } else if (DB_UNDO(op)) {
00306                 is_done = 0;
00307 
00308                 /* If file does not exist, there is nothing to undo. */
00309                 if (CDB___os_exists(real_name, NULL) != 0)
00310                         goto done;
00311 
00312                 /*
00313                  * Before we can look at anything on disk, we have to check
00314                  * if there is a valid dbp for this, and if there is, we'd
00315                  * better flush it.
00316                  */
00317                 dbp = NULL;
00318                 if ((ret =
00319                     CDB___db_fileid_to_db(dbenv, &dbp, argp->fileid, 0)) == 0)
00320                         (void)dbp->sync(dbp, 0);
00321 
00322                 /*
00323                  * We need to make sure that we do not remove a file that
00324                  * someone else created.   If the file is 0-length, then we
00325                  * can assume that we created it and remove it.  If it is
00326                  * not 0-length, then we need to check the LSN and make
00327                  * sure that it's the file we created.
00328                  */
00329                 if ((ret = CDB___os_open(dbenv, real_name, 0, 0, &fh)) != 0)
00330                         goto out;
00331                 if ((ret = CDB___os_ioinfo(dbenv,
00332                     real_name, &fh, &mb, &b, &io)) != 0)
00333                         goto out;
00334                 if (mb != 0 || b != 0) {
00335                         /* The file has something in it. */
00336                         if ((ret = CDB___os_seek(dbenv, &fh,
00337                             pagesize, argp->pgno, 0, 0, DB_OS_SEEK_SET)) != 0)
00338                                 goto out;
00339                         if ((ret = CDB___os_read(dbenv, &fh,
00340                             &ondisk, sizeof(ondisk), &nr)) != 0)
00341                                 goto out;
00342                         if (CDB_log_compare(&ondisk.lsn, lsnp) != 0)
00343                                 is_done = 1;
00344                 }
00345 
00346                 /*
00347                  * Must close here, because unlink with the file open fails
00348                  * on some systems.
00349                  */
00350                 if ((ret = CDB___os_closehandle(&fh)) != 0)
00351                         goto out;
00352 
00353                 if (!is_done) {
00354                         /*
00355                          * On some systems, you cannot unlink an open file so
00356                          * we close the fd in the dbp here and make sure we
00357                          * don't try to close it again.  First, check for a
00358                          * saved_open_fhp, then close down the mpool.
00359                          */
00360                         if (dbp != NULL && dbp->saved_open_fhp != NULL &&
00361                             F_ISSET(dbp->saved_open_fhp, DB_FH_VALID) &&
00362                             (ret = CDB___os_closehandle(dbp->saved_open_fhp)) != 0)
00363                                 goto out;
00364                         if (dbp != NULL && dbp->mpf != NULL) {
00365                                 (void)CDB___memp_fremove(dbp->mpf);
00366                                 if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
00367                                         goto out;
00368                                 F_SET(dbp, DB_AM_DISCARD);
00369                                 dbp->mpf = NULL;
00370                         }
00371                         if ((ret = CDB___os_unlink(dbenv, real_name)) != 0)
00372                                 goto out;
00373                 }
00374         }
00375 
00376 done:   *lsnp = argp->prev_lsn;
00377         ret = 0;
00378 
00379 out:    if (argp != NULL)
00380                 CDB___os_free(argp, sizeof(*argp));
00381         if (real_name != NULL)
00382                 CDB___os_freestr(real_name);
00383         if (F_ISSET(&fh, DB_FH_VALID))
00384                 (void)CDB___os_closehandle(&fh);
00385         return (ret);
00386 }
00387 
00388 /*
00389  * CDB___crdel_delete_recover --
00390  *      Recovery function for delete.
00391  *
00392  * PUBLIC: int CDB___crdel_delete_recover
00393  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00394  */
00395 int
00396 CDB___crdel_delete_recover(dbenv, dbtp, lsnp, op, info)
00397         DB_ENV *dbenv;
00398         DBT *dbtp;
00399         DB_LSN *lsnp;
00400         db_recops op;
00401         void *info;
00402 {
00403         DB *dbp;
00404         __crdel_delete_args *argp;
00405         int ret;
00406         char *backup, *real_back, *real_name;
00407 
00408         REC_PRINT(CDB___crdel_delete_print);
00409 
00410         backup = real_back = real_name = NULL;
00411         if ((ret = CDB___crdel_delete_read(dbenv, dbtp->data, &argp)) != 0)
00412                 goto out;
00413 
00414         if (DB_REDO(op)) {
00415                 /*
00416                  * On a recovery, as we recreate what was going on, we
00417                  * recreate the creation of the file.  And so, even though
00418                  * it committed, we need to delete it.  Try to delete it,
00419                  * but it is not an error if that delete fails.
00420                  */
00421                 if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00422                     NULL, argp->name.data, 0, NULL, &real_name)) != 0)
00423                         goto out;
00424                 if (CDB___os_exists(real_name, NULL) == 0) {
00425                         /*
00426                          * On Windows, the underlying file must be
00427                          * closed to perform a remove.
00428                          */
00429                         if ((ret = CDB___db_fileid_to_db(
00430                             dbenv, &dbp, argp->fileid, 0)) != 0)
00431                                 goto out;
00432                         (void)CDB___memp_fremove(dbp->mpf);
00433                         if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
00434                                 goto out;
00435                         dbp->mpf = NULL;
00436                         if ((ret = CDB___os_unlink(dbenv, real_name)) != 0)
00437                                 goto out;
00438                 }
00439                 /*
00440                  * The transaction committed, so the only thing that might
00441                  * be true is that the backup file is still around.  Try
00442                  * to delete it, but it's not an error if that delete fails.
00443                  */
00444                 if ((ret =  CDB___db_backup_name(dbenv, argp->name.data,
00445                     &backup, lsnp)) != 0)
00446                         goto out;
00447                 if ((ret = CDB___db_appname(dbenv,
00448                     DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
00449                         goto out;
00450                 if (CDB___os_exists(real_back, NULL) == 0)
00451                         if ((ret = CDB___os_unlink(dbenv, real_back)) != 0)
00452                                 goto out;
00453                 if ((ret = CDB___db_txnlist_delete(dbenv, info,
00454                     argp->name.data, TXNLIST_INVALID_ID, 1)) != 0)
00455                         goto out;
00456         } else if (DB_UNDO(op)) {
00457                 /*
00458                  * Trying to undo.  File may or may not have been deleted.
00459                  * Try to move the backup to the original.  If the backup
00460                  * exists, then this is right.  If it doesn't exist, then
00461                  * nothing will happen and that's OK.
00462                  */
00463                 if ((ret =  CDB___db_backup_name(dbenv, argp->name.data,
00464                     &backup, lsnp)) != 0)
00465                         goto out;
00466                 if ((ret = CDB___db_appname(dbenv,
00467                     DB_APP_DATA, NULL, backup, 0, NULL, &real_back)) != 0)
00468                         goto out;
00469                 if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00470                     NULL, argp->name.data, 0, NULL, &real_name)) != 0)
00471                         goto out;
00472                 if (CDB___os_exists(real_back, NULL) == 0)
00473                         if ((ret =
00474                              CDB___os_rename(dbenv, real_back, real_name)) != 0)
00475                                 goto out;
00476         }
00477 
00478         *lsnp = argp->prev_lsn;
00479         ret = 0;
00480 
00481 out:    if (argp != NULL)
00482                 CDB___os_free(argp, sizeof(*argp));
00483         if (backup != NULL)
00484                 CDB___os_freestr(backup);
00485         if (real_back != NULL)
00486                 CDB___os_freestr(real_back);
00487         if (real_name != NULL)
00488                 CDB___os_freestr(real_name);
00489         return (ret);
00490 }
00491 /*
00492  * CDB___crdel_rename_recover --
00493  *      Recovery function for rename.
00494  *
00495  * PUBLIC: int CDB___crdel_rename_recover
00496  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
00497  */
00498 int
00499 CDB___crdel_rename_recover(dbenv, dbtp, lsnp, op, info)
00500         DB_ENV *dbenv;
00501         DBT *dbtp;
00502         DB_LSN *lsnp;
00503         db_recops op;
00504         void *info;
00505 {
00506         DB *dbp;
00507         __crdel_rename_args *argp;
00508         char *new_name, *real_name;
00509         int ret, set;
00510 
00511         COMPQUIET(info, NULL);
00512 
00513         REC_PRINT(CDB___crdel_rename_print);
00514         if ((ret = CDB___crdel_rename_read(dbenv, dbtp->data, &argp)) != 0)
00515                 goto out;
00516 
00517         if ((ret = CDB___db_fileid_to_db(dbenv, &dbp, argp->fileid, 0)) != 0)
00518                 goto out;
00519         if (DB_REDO(op)) {
00520                 /*
00521                  * We don't use the dbp parameter to CDB___log_filelist_update
00522                  * in the rename case, so passing NULL for it is OK.
00523                  */
00524                 if ((ret = CDB___log_filelist_update(dbenv, NULL,
00525                     argp->fileid, argp->newname.data, &set)) != 0)
00526                         goto out;
00527                 if (set != 0) {
00528                         if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00529                             NULL, argp->name.data, 0, NULL, &real_name)) != 0)
00530                                 goto out;
00531                         if (CDB___os_exists(real_name, NULL) == 0) {
00532                                 if ((ret = CDB___db_appname(dbenv,
00533                                     DB_APP_DATA, NULL, argp->newname.data,
00534                                     0, NULL, &new_name)) != 0)
00535                                         goto out;
00536                                 /*
00537                                  * On Windows, the underlying file
00538                                  * must be closed to perform a remove.
00539                                  * The db will be closed by a
00540                                  * CDB_log_register record.  Rename
00541                                  * has exclusive access to the db.
00542                                  */
00543                                 (void)CDB___memp_fremove(dbp->mpf);
00544                                 if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
00545                                         goto out;
00546                                 dbp->mpf = NULL;
00547                                 if ((ret = CDB___os_rename(dbenv,
00548                                     real_name, new_name)) != 0)
00549                                         goto out;
00550                         }
00551                 }
00552         } else {
00553                 /*
00554                  * We don't use the dbp parameter to CDB___log_filelist_update
00555                  * in the rename case, so passing NULL for it is OK.
00556                  */
00557                 if ((ret = CDB___log_filelist_update(dbenv, NULL,
00558                     argp->fileid, argp->name.data, &set)) != 0)
00559                         goto out;
00560                 if (set != 0) {
00561                         if ((ret = CDB___db_appname(dbenv, DB_APP_DATA,
00562                             NULL, argp->newname.data, 0, NULL, &new_name)) != 0)
00563                                 goto out;
00564                         if (CDB___os_exists(new_name, NULL) == 0) {
00565                                 if ((ret = CDB___db_appname(dbenv,
00566                                     DB_APP_DATA, NULL, argp->name.data,
00567                                     0, NULL, &real_name)) != 0)
00568                                         goto out;
00569                                 /*
00570                                  * On Windows, the underlying file
00571                                  * must be closed to perform a remove.
00572                                  * The file may have already been closed
00573                                  * if we are aborting the transaction.
00574                                  */
00575                                 if (dbp->mpf != NULL) {
00576                                         (void)CDB___memp_fremove(dbp->mpf);
00577                                         if ((ret = CDB_memp_fclose(dbp->mpf)) != 0)
00578                                                 goto out;
00579                                         dbp->mpf = NULL;
00580                                 }
00581                                 if ((ret = CDB___os_rename(dbenv,
00582                                     new_name, real_name)) != 0)
00583                                         goto out;
00584                         }
00585                 }
00586         }
00587 
00588         *lsnp = argp->prev_lsn;
00589         ret = 0;
00590 
00591 out:    if (argp != NULL)
00592                 CDB___os_free(argp, sizeof(*argp));
00593         return (ret);
00594 }

Generated on Sun Jun 8 10:56:35 2008 for GNUmifluz by  doxygen 1.5.5