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

db_rename.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: db_rename.c,v 12.11 2005/10/07 20:21:22 ubell Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 #include <string.h>
00015 #endif
00016 
00017 #include "db_int.h"
00018 #include "dbinc/db_page.h"
00019 #include "dbinc/db_shash.h"
00020 #include "dbinc/db_am.h"
00021 #include "dbinc/fop.h"
00022 #include "dbinc/lock.h"
00023 #include "dbinc/log.h"
00024 #include "dbinc/mp.h"
00025 
00026 static int __db_subdb_rename __P((DB *,
00027                DB_TXN *, const char *, const char *, const char *));
00028 
00029 /*
00030  * __env_dbrename_pp
00031  *      DB_ENV->dbrename pre/post processing.
00032  *
00033  * PUBLIC: int __env_dbrename_pp __P((DB_ENV *, DB_TXN *,
00034  * PUBLIC:     const char *, const char *, const char *, u_int32_t));
00035  */
00036 int
00037 __env_dbrename_pp(dbenv, txn, name, subdb, newname, flags)
00038         DB_ENV *dbenv;
00039         DB_TXN *txn;
00040         const char *name, *subdb, *newname;
00041         u_int32_t flags;
00042 {
00043         DB *dbp;
00044         DB_THREAD_INFO *ip;
00045         int handle_check, ret, t_ret, txn_local;
00046 
00047         dbp = NULL;
00048         txn_local = 0;
00049 
00050         PANIC_CHECK(dbenv);
00051         ENV_ILLEGAL_BEFORE_OPEN(dbenv, "DB_ENV->dbrename");
00052 
00053         /*
00054          * The actual argument checking is simple, do it inline, outside of
00055          * the replication block.
00056          */
00057         if ((ret = __db_fchk(dbenv, "DB->rename", flags, DB_AUTO_COMMIT)) != 0)
00058                 return (ret);
00059 
00060         ENV_ENTER(dbenv, ip);
00061 
00062         /* Check for replication block. */
00063         handle_check = IS_ENV_REPLICATED(dbenv);
00064         if (handle_check && (ret = __env_rep_enter(dbenv, 1)) != 0) {
00065                 handle_check = 0;
00066                 goto err;
00067         }
00068 
00069         /*
00070          * Create local transaction as necessary, check for consistent
00071          * transaction usage.
00072          */
00073         if (IS_ENV_AUTO_COMMIT(dbenv, txn, flags)) {
00074                 if ((ret = __db_txn_auto_init(dbenv, &txn)) != 0)
00075                         goto err;
00076                 txn_local = 1;
00077         } else
00078                 if (txn != NULL && !TXN_ON(dbenv)) {
00079                         ret = __db_not_txn_env(dbenv);
00080                         goto err;
00081                 }
00082 
00083         LF_CLR(DB_AUTO_COMMIT);
00084 
00085         if ((ret = db_create(&dbp, dbenv, 0)) != 0)
00086                 goto err;
00087 
00088         ret = __db_rename_int(dbp, txn, name, subdb, newname);
00089 
00090         if (txn_local) {
00091                 /*
00092                  * We created the DBP here and when we commit/abort, we'll
00093                  * release all the transactional locks, including the handle
00094                  * lock; mark the handle cleared explicitly.
00095                  */
00096                 LOCK_INIT(dbp->handle_lock);
00097                 dbp->lid = DB_LOCK_INVALIDID;
00098         } else if (txn != NULL) {
00099                 /*
00100                  * We created this handle locally so we need to close it
00101                  * and clean it up.  Unfortunately, it's holding transactional
00102                  * locks that need to persist until the end of transaction.
00103                  * If we invalidate the locker id (dbp->lid), then the close
00104                  * won't free these locks prematurely.
00105                  */
00106                  dbp->lid = DB_LOCK_INVALIDID;
00107         }
00108 
00109 err:    if (txn_local && (t_ret =
00110             __db_txn_auto_resolve(dbenv, txn, 0, ret)) != 0 && ret == 0)
00111                 ret = t_ret;
00112 
00113         /*
00114          * We never opened this dbp for real, so don't include a transaction
00115          * handle, and use NOSYNC to avoid calling into mpool.
00116          *
00117          * !!!
00118          * Note we're reversing the order of operations: we started the txn and
00119          * then opened the DB handle; we're resolving the txn and then closing
00120          * closing the DB handle -- it's safer.
00121          */
00122         if (dbp != NULL &&
00123             (t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
00124                 ret = t_ret;
00125 
00126         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00127                 ret = t_ret;
00128 
00129         ENV_LEAVE(dbenv, ip);
00130         return (ret);
00131 }
00132 
00133 /*
00134  * __db_rename_pp
00135  *      DB->rename pre/post processing.
00136  *
00137  * PUBLIC: int __db_rename_pp __P((DB *,
00138  * PUBLIC:     const char *, const char *, const char *, u_int32_t));
00139  */
00140 int
00141 __db_rename_pp(dbp, name, subdb, newname, flags)
00142         DB *dbp;
00143         const char *name, *subdb, *newname;
00144         u_int32_t flags;
00145 {
00146         DB_ENV *dbenv;
00147         DB_THREAD_INFO *ip;
00148         int handle_check, ret, t_ret;
00149 
00150         dbenv = dbp->dbenv;
00151         handle_check = 0;
00152 
00153         PANIC_CHECK(dbenv);
00154 
00155         /*
00156          * Validate arguments, continuing to destroy the handle on failure.
00157          *
00158          * Cannot use DB_ILLEGAL_AFTER_OPEN directly because it returns.
00159          *
00160          * !!!
00161          * We have a serious problem if we're here with a handle used to open
00162          * a database -- we'll destroy the handle, and the application won't
00163          * ever be able to close the database.
00164          */
00165         if (F_ISSET(dbp, DB_AM_OPEN_CALLED))
00166                 return (__db_mi_open(dbenv, "DB->rename", 1));
00167 
00168         /* Validate arguments. */
00169         if ((ret = __db_fchk(dbenv, "DB->rename", flags, 0)) != 0)
00170                 return (ret);
00171 
00172         /* Check for consistent transaction usage. */
00173         if ((ret = __db_check_txn(dbp, NULL, DB_LOCK_INVALIDID, 0)) != 0)
00174                 return (ret);
00175 
00176         ENV_ENTER(dbenv, ip);
00177 
00178         handle_check = IS_ENV_REPLICATED(dbenv);
00179         if (handle_check && (ret = __db_rep_enter(dbp, 1, 1, 0)) != 0) {
00180                 handle_check = 0;
00181                 goto err;
00182         }
00183 
00184         /* Rename the file. */
00185         ret = __db_rename(dbp, NULL, name, subdb, newname);
00186 
00187         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00188                 ret = t_ret;
00189 err:    ENV_LEAVE(dbenv, ip);
00190         return (ret);
00191 }
00192 
00193 /*
00194  * __db_rename
00195  *      DB->rename method.
00196  *
00197  * PUBLIC: int __db_rename
00198  * PUBLIC:     __P((DB *, DB_TXN *, const char *, const char *, const char *));
00199  */
00200 int
00201 __db_rename(dbp, txn, name, subdb, newname)
00202         DB *dbp;
00203         DB_TXN *txn;
00204         const char *name, *subdb, *newname;
00205 {
00206         int ret, t_ret;
00207 
00208         ret = __db_rename_int(dbp, txn, name, subdb, newname);
00209 
00210         if ((t_ret = __db_close(dbp, txn, DB_NOSYNC)) != 0 && ret == 0)
00211                 ret = t_ret;
00212 
00213         return (ret);
00214 }
00215 
00216 /*
00217  * __db_rename_int
00218  *      Worker function for DB->rename method; the close of the dbp is
00219  * left in the wrapper routine.
00220  *
00221  * PUBLIC: int __db_rename_int
00222  * PUBLIC:     __P((DB *, DB_TXN *, const char *, const char *, const char *));
00223  */
00224 int
00225 __db_rename_int(dbp, txn, name, subdb, newname)
00226         DB *dbp;
00227         DB_TXN *txn;
00228         const char *name, *subdb, *newname;
00229 {
00230         DB_ENV *dbenv;
00231         int ret;
00232         char *old, *real_name;
00233 
00234         dbenv = dbp->dbenv;
00235         real_name = NULL;
00236 
00237         DB_TEST_RECOVERY(dbp, DB_TEST_PREDESTROY, ret, name);
00238 
00239         if (name == NULL && subdb == NULL) {
00240                 __db_err(dbenv, "Rename on temporary files invalid");
00241                 ret = EINVAL;
00242                 goto err;
00243         }
00244 
00245         if (name == NULL)
00246                 MAKE_INMEM(dbp);
00247         else if (subdb != NULL) {
00248                 ret = __db_subdb_rename(dbp, txn, name, subdb, newname);
00249                 goto err;
00250         }
00251 
00252         /*
00253          * From here on down, this pertains to files or in-memory databases.
00254          *
00255          * Find the real name of the file.
00256          */
00257         if (F_ISSET(dbp, DB_AM_INMEM)) {
00258                 old = (char *)subdb;
00259                 real_name = (char *)subdb;
00260         } else {
00261                 if ((ret = __db_appname(dbenv,
00262                     DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
00263                         goto err;
00264                 old = (char *)name;
00265         }
00266 
00267         if ((ret = __fop_remove_setup(dbp, txn, real_name, 0)) != 0)
00268                 goto err;
00269 
00270         if (dbp->db_am_rename != NULL &&
00271             (ret = dbp->db_am_rename(dbp, txn, name, subdb, newname)) != 0)
00272                 goto err;
00273 
00274         /*
00275          * The transactional case and non-transactional case are
00276          * quite different.  In the non-transactional case, we simply
00277          * do the rename.  In the transactional case, since we need
00278          * the ability to back out and maintain locking, we have to
00279          * create a temporary object as a placeholder.  This is all
00280          * taken care of in the fop layer.
00281          */
00282         if (txn != NULL) {
00283                 if ((ret = __fop_dummy(dbp, txn, old, newname, 0)) != 0)
00284                         goto err;
00285         } else {
00286                 if ((ret = __fop_dbrename(dbp, old, newname)) != 0)
00287                         goto err;
00288         }
00289 
00290         /*
00291          * I am pretty sure that we haven't gotten a dbreg id, so calling
00292          * dbreg_filelist_update is not necessary.
00293          */
00294         DB_ASSERT(dbp->log_filename == NULL ||
00295             dbp->log_filename->id == DB_LOGFILEID_INVALID);
00296 
00297         DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, newname);
00298 
00299 DB_TEST_RECOVERY_LABEL
00300 err:    if (!F_ISSET(dbp, DB_AM_INMEM) && real_name != NULL)
00301                 __os_free(dbenv, real_name);
00302 
00303         return (ret);
00304 }
00305 
00306 /*
00307  * __db_subdb_rename --
00308  *      Rename a subdatabase.
00309  */
00310 static int
00311 __db_subdb_rename(dbp, txn, name, subdb, newname)
00312         DB *dbp;
00313         DB_TXN *txn;
00314         const char *name, *subdb, *newname;
00315 {
00316         DB *mdbp;
00317         DB_ENV *dbenv;
00318         PAGE *meta;
00319         int ret, t_ret;
00320 
00321         mdbp = NULL;
00322         meta = NULL;
00323         dbenv = dbp->dbenv;
00324 
00325         /*
00326          * We have not opened this dbp so it isn't marked as a subdb,
00327          * but it ought to be.
00328          */
00329         F_SET(dbp, DB_AM_SUBDB);
00330 
00331         /*
00332          * Rename the entry in the main database.  We need to first
00333          * get the meta-data page number (via MU_OPEN) so that we can
00334          * read the meta-data page and obtain a handle lock.  Once we've
00335          * done that, we can proceed to do the rename in the master.
00336          */
00337         if ((ret = __db_master_open(dbp, txn, name, 0, 0, &mdbp)) != 0)
00338                 goto err;
00339 
00340         if ((ret = __db_master_update(mdbp, dbp, txn, subdb, dbp->type,
00341             MU_OPEN, NULL, 0)) != 0)
00342                 goto err;
00343 
00344         if ((ret = __memp_fget(mdbp->mpf, &dbp->meta_pgno, 0, &meta)) != 0)
00345                 goto err;
00346         memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
00347         if ((ret = __fop_lock_handle(dbenv,
00348             dbp, mdbp->lid, DB_LOCK_WRITE, NULL, NOWAIT_FLAG(txn))) != 0)
00349                 goto err;
00350 
00351         ret = __memp_fput(mdbp->mpf, meta, 0);
00352         meta = NULL;
00353         if (ret != 0)
00354                 goto err;
00355 
00356         if ((ret = __db_master_update(mdbp, dbp, txn,
00357             subdb, dbp->type, MU_RENAME, newname, 0)) != 0)
00358                 goto err;
00359 
00360         DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, name);
00361 
00362 DB_TEST_RECOVERY_LABEL
00363 err:
00364         if (meta != NULL &&
00365             (t_ret = __memp_fput(mdbp->mpf, meta, 0)) != 0 && ret == 0)
00366                 ret = t_ret;
00367 
00368         if (mdbp != NULL &&
00369             (t_ret = __db_close(mdbp, txn, DB_NOSYNC)) != 0 && ret == 0)
00370                 ret = t_ret;
00371 
00372         return (ret);
00373 }

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