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

db_truncate.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_truncate.c,v 12.10 2005/10/21 19:22:59 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/btree.h"
00022 #include "dbinc/hash.h"
00023 #include "dbinc/qam.h"
00024 #include "dbinc/lock.h"
00025 #include "dbinc/log.h"
00026 #include "dbinc/txn.h"
00027 
00028 static int __db_cursor_check __P((DB *));
00029 
00030 /*
00031  * __db_truncate_pp
00032  *      DB->truncate pre/post processing.
00033  *
00034  * PUBLIC: int __db_truncate_pp __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
00035  */
00036 int
00037 __db_truncate_pp(dbp, txn, countp, flags)
00038         DB *dbp;
00039         DB_TXN *txn;
00040         u_int32_t *countp, flags;
00041 {
00042         DB_ENV *dbenv;
00043         DB_THREAD_INFO *ip;
00044         int handle_check, ret, t_ret, txn_local;
00045 
00046         dbenv = dbp->dbenv;
00047         txn_local = 0;
00048         handle_check = 0;
00049 
00050         PANIC_CHECK(dbenv);
00051         STRIP_AUTO_COMMIT(flags);
00052 
00053         /* Check for invalid flags. */
00054         if (F_ISSET(dbp, DB_AM_SECONDARY)) {
00055                 __db_err(dbenv,
00056                     "DB->truncate forbidden on secondary indices");
00057                 return (EINVAL);
00058         }
00059         if ((ret = __db_fchk(dbenv, "DB->truncate", flags, 0)) != 0)
00060                 return (ret);
00061 
00062         ENV_ENTER(dbenv, ip);
00063 
00064         /*
00065          * Make sure there are no active cursors on this db.  Since we drop
00066          * pages we cannot really adjust cursors.
00067          */
00068         if (__db_cursor_check(dbp) != 0) {
00069                 __db_err(dbenv,
00070                      "DB->truncate not permitted with active cursors");
00071                 goto err;
00072         }
00073 
00074 #if CONFIG_TEST
00075         if (IS_REP_MASTER(dbenv))
00076                 DB_TEST_WAIT(dbenv, dbenv->test_check);
00077 #endif
00078         /* Check for replication block. */
00079         handle_check = IS_ENV_REPLICATED(dbenv);
00080         if (handle_check &&
00081             (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
00082                 handle_check = 0;
00083                 goto err;
00084         }
00085 
00086         /*
00087          * Check for changes to a read-only database.
00088          * This must be after the replication block so that we
00089          * cannot race master/client state changes.
00090          */
00091         if (DB_IS_READONLY(dbp)) {
00092                 ret = __db_rdonly(dbenv, "DB->truncate");
00093                 goto err;
00094         }
00095 
00096         /*
00097          * Create local transaction as necessary, check for consistent
00098          * transaction usage.
00099          */
00100         if (IS_DB_AUTO_COMMIT(dbp, txn)) {
00101                 if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
00102                         goto err;
00103                 txn_local = 1;
00104         }
00105 
00106         /* Check for consistent transaction usage. */
00107         if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
00108                 goto err;
00109 
00110         ret = __db_truncate(dbp, txn, countp);
00111 
00112 err:    if (txn_local &&
00113             (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
00114                 ret = t_ret;
00115 
00116         /* Release replication block. */
00117         if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
00118                 ret = t_ret;
00119 
00120         ENV_LEAVE(dbenv, ip);
00121         return (ret);
00122 }
00123 
00124 /*
00125  * __db_truncate
00126  *      DB->truncate.
00127  *
00128  * PUBLIC: int __db_truncate __P((DB *, DB_TXN *, u_int32_t *));
00129  */
00130 int
00131 __db_truncate(dbp, txn, countp)
00132         DB *dbp;
00133         DB_TXN *txn;
00134         u_int32_t *countp;
00135 {
00136         DB *sdbp;
00137         DBC *dbc;
00138         DB_ENV *dbenv;
00139         u_int32_t scount;
00140         int ret, t_ret;
00141 
00142         dbenv = dbp->dbenv;
00143         dbc = NULL;
00144         ret = 0;
00145 
00146         /*
00147          * Run through all secondaries and truncate them first.  The count
00148          * returned is the count of the primary only.  QUEUE uses normal
00149          * processing to truncate so it will update the secondaries normally.
00150          */
00151         if (dbp->type != DB_QUEUE && LIST_FIRST(&dbp->s_secondaries) != NULL) {
00152                 if ((ret = __db_s_first(dbp, &sdbp)) != 0)
00153                         return (ret);
00154                 for (; sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp))
00155                         if ((ret = __db_truncate(sdbp, txn, &scount)) != 0)
00156                                 break;
00157                 if (sdbp != NULL)
00158                         (void)__db_s_done(sdbp);
00159                 if (ret != 0)
00160                         return (ret);
00161         }
00162 
00163         DB_TEST_RECOVERY(dbp, DB_TEST_PREDESTROY, ret, NULL);
00164 
00165         /* Acquire a cursor. */
00166         if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
00167                 return (ret);
00168 
00169         DEBUG_LWRITE(dbc, txn, "DB->truncate", NULL, NULL, 0);
00170 
00171         switch (dbp->type) {
00172         case DB_BTREE:
00173         case DB_RECNO:
00174                 ret = __bam_truncate(dbc, countp);
00175                 break;
00176         case DB_HASH:
00177                 ret = __ham_truncate(dbc, countp);
00178                 break;
00179         case DB_QUEUE:
00180                 ret = __qam_truncate(dbc, countp);
00181                 break;
00182         case DB_UNKNOWN:
00183         default:
00184                 ret = __db_unknown_type(dbenv, "DB->truncate", dbp->type);
00185                 break;
00186         }
00187 
00188         /* Discard the cursor. */
00189         if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
00190                 ret = t_ret;
00191 
00192         DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, NULL);
00193 
00194 DB_TEST_RECOVERY_LABEL
00195 
00196         return (ret);
00197 }
00198 
00199 /*
00200  * __db_cursor_check --
00201  *      See if there are any active cursors on this db.
00202  */
00203 static int
00204 __db_cursor_check(dbp)
00205         DB *dbp;
00206 {
00207         DB *ldbp;
00208         DBC *dbc;
00209         DB_ENV *dbenv;
00210         int found;
00211 
00212         dbenv = dbp->dbenv;
00213 
00214         MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
00215         for (found = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid);
00216             ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
00217             ldbp = LIST_NEXT(ldbp, dblistlinks)) {
00218                 MUTEX_LOCK(dbenv, dbp->mutex);
00219                 for (dbc = TAILQ_FIRST(&ldbp->active_queue);
00220                     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
00221                         if (IS_INITIALIZED(dbc)) {
00222                                 found = 1;
00223                                 break;
00224                         }
00225                 }
00226                 MUTEX_UNLOCK(dbenv, dbp->mutex);
00227                 if (found == 1)
00228                         break;
00229         }
00230         MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
00231 
00232         return (found);
00233 }

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