db_truncate.c 4.93 KB
Newer Older
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
4
 * Copyright (c) 2001-2005
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
5
 *	Sleepycat Software.  All rights reserved.
jimw@mysql.com's avatar
jimw@mysql.com committed
6
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
7
 * $Id: db_truncate.c,v 12.10 2005/10/21 19:22:59 bostic Exp $
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
8 9 10 11 12 13
 */

#include "db_config.h"

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
jimw@mysql.com's avatar
jimw@mysql.com committed
14 15

#include <string.h>
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
16 17 18 19
#endif

#include "db_int.h"
#include "dbinc/db_page.h"
jimw@mysql.com's avatar
jimw@mysql.com committed
20
#include "dbinc/db_shash.h"
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
21 22 23
#include "dbinc/btree.h"
#include "dbinc/hash.h"
#include "dbinc/qam.h"
jimw@mysql.com's avatar
jimw@mysql.com committed
24 25
#include "dbinc/lock.h"
#include "dbinc/log.h"
jimw@mysql.com's avatar
jimw@mysql.com committed
26 27 28
#include "dbinc/txn.h"

static int __db_cursor_check __P((DB *));
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
29 30

/*
jimw@mysql.com's avatar
jimw@mysql.com committed
31 32
 * __db_truncate_pp
 *	DB->truncate pre/post processing.
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
33
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
34
 * PUBLIC: int __db_truncate_pp __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
35 36
 */
int
jimw@mysql.com's avatar
jimw@mysql.com committed
37
__db_truncate_pp(dbp, txn, countp, flags)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
38 39 40 41 42
	DB *dbp;
	DB_TXN *txn;
	u_int32_t *countp, flags;
{
	DB_ENV *dbenv;
jimw@mysql.com's avatar
jimw@mysql.com committed
43 44
	DB_THREAD_INFO *ip;
	int handle_check, ret, t_ret, txn_local;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
45 46

	dbenv = dbp->dbenv;
jimw@mysql.com's avatar
jimw@mysql.com committed
47 48
	txn_local = 0;
	handle_check = 0;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
49 50

	PANIC_CHECK(dbenv);
jimw@mysql.com's avatar
jimw@mysql.com committed
51
	STRIP_AUTO_COMMIT(flags);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
52 53

	/* Check for invalid flags. */
jimw@mysql.com's avatar
jimw@mysql.com committed
54 55
	if (F_ISSET(dbp, DB_AM_SECONDARY)) {
		__db_err(dbenv,
jimw@mysql.com's avatar
jimw@mysql.com committed
56
		    "DB->truncate forbidden on secondary indices");
jimw@mysql.com's avatar
jimw@mysql.com committed
57 58
		return (EINVAL);
	}
jimw@mysql.com's avatar
jimw@mysql.com committed
59
	if ((ret = __db_fchk(dbenv, "DB->truncate", flags, 0)) != 0)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
60 61
		return (ret);

jimw@mysql.com's avatar
jimw@mysql.com committed
62 63
	ENV_ENTER(dbenv, ip);

jimw@mysql.com's avatar
jimw@mysql.com committed
64 65 66 67 68 69 70
	/*
	 * Make sure there are no active cursors on this db.  Since we drop
	 * pages we cannot really adjust cursors.
	 */
	if (__db_cursor_check(dbp) != 0) {
		__db_err(dbenv,
		     "DB->truncate not permitted with active cursors");
jimw@mysql.com's avatar
jimw@mysql.com committed
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
		goto err;
	}

#if CONFIG_TEST
	if (IS_REP_MASTER(dbenv))
		DB_TEST_WAIT(dbenv, dbenv->test_check);
#endif
	/* Check for replication block. */
	handle_check = IS_ENV_REPLICATED(dbenv);
	if (handle_check &&
	    (ret = __db_rep_enter(dbp, 1, 0, txn != NULL)) != 0) {
		handle_check = 0;
		goto err;
	}

	/*
	 * Check for changes to a read-only database.
	 * This must be after the replication block so that we
	 * cannot race master/client state changes.
	 */
	if (DB_IS_READONLY(dbp)) {
		ret = __db_rdonly(dbenv, "DB->truncate");
		goto err;
jimw@mysql.com's avatar
jimw@mysql.com committed
94 95
	}

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
96 97 98 99
	/*
	 * Create local transaction as necessary, check for consistent
	 * transaction usage.
	 */
jimw@mysql.com's avatar
jimw@mysql.com committed
100 101
	if (IS_DB_AUTO_COMMIT(dbp, txn)) {
		if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0)
jimw@mysql.com's avatar
jimw@mysql.com committed
102
			goto err;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
103
		txn_local = 1;
jimw@mysql.com's avatar
jimw@mysql.com committed
104 105
	}

jimw@mysql.com's avatar
jimw@mysql.com committed
106 107
	/* Check for consistent transaction usage. */
	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)
jimw@mysql.com's avatar
jimw@mysql.com committed
108 109 110 111
		goto err;

	ret = __db_truncate(dbp, txn, countp);

jimw@mysql.com's avatar
jimw@mysql.com committed
112 113 114 115 116 117 118
err:	if (txn_local &&
	    (t_ret = __db_txn_auto_resolve(dbenv, txn, 0, ret)) && ret == 0)
		ret = t_ret;

	/* Release replication block. */
	if (handle_check && (t_ret = __env_db_rep_exit(dbenv)) != 0 && ret == 0)
		ret = t_ret;
jimw@mysql.com's avatar
jimw@mysql.com committed
119

jimw@mysql.com's avatar
jimw@mysql.com committed
120 121
	ENV_LEAVE(dbenv, ip);
	return (ret);
jimw@mysql.com's avatar
jimw@mysql.com committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
}

/*
 * __db_truncate
 *	DB->truncate.
 *
 * PUBLIC: int __db_truncate __P((DB *, DB_TXN *, u_int32_t *));
 */
int
__db_truncate(dbp, txn, countp)
	DB *dbp;
	DB_TXN *txn;
	u_int32_t *countp;
{
	DB *sdbp;
	DBC *dbc;
	DB_ENV *dbenv;
	u_int32_t scount;
	int ret, t_ret;

	dbenv = dbp->dbenv;
	dbc = NULL;
	ret = 0;

	/*
	 * Run through all secondaries and truncate them first.  The count
	 * returned is the count of the primary only.  QUEUE uses normal
	 * processing to truncate so it will update the secondaries normally.
	 */
	if (dbp->type != DB_QUEUE && LIST_FIRST(&dbp->s_secondaries) != NULL) {
jimw@mysql.com's avatar
jimw@mysql.com committed
152 153 154
		if ((ret = __db_s_first(dbp, &sdbp)) != 0)
			return (ret);
		for (; sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp))
jimw@mysql.com's avatar
jimw@mysql.com committed
155 156 157 158 159 160 161
			if ((ret = __db_truncate(sdbp, txn, &scount)) != 0)
				break;
		if (sdbp != NULL)
			(void)__db_s_done(sdbp);
		if (ret != 0)
			return (ret);
	}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
162 163

	DB_TEST_RECOVERY(dbp, DB_TEST_PREDESTROY, ret, NULL);
jimw@mysql.com's avatar
jimw@mysql.com committed
164 165 166 167 168 169 170

	/* Acquire a cursor. */
	if ((ret = __db_cursor(dbp, txn, &dbc, 0)) != 0)
		return (ret);

	DEBUG_LWRITE(dbc, txn, "DB->truncate", NULL, NULL, 0);

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
171
	switch (dbp->type) {
jimw@mysql.com's avatar
jimw@mysql.com committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185
	case DB_BTREE:
	case DB_RECNO:
		ret = __bam_truncate(dbc, countp);
		break;
	case DB_HASH:
		ret = __ham_truncate(dbc, countp);
		break;
	case DB_QUEUE:
		ret = __qam_truncate(dbc, countp);
		break;
	case DB_UNKNOWN:
	default:
		ret = __db_unknown_type(dbenv, "DB->truncate", dbp->type);
		break;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
186
	}
jimw@mysql.com's avatar
jimw@mysql.com committed
187 188 189 190 191

	/* Discard the cursor. */
	if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)
		ret = t_ret;

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
192 193 194 195 196 197
	DB_TEST_RECOVERY(dbp, DB_TEST_POSTDESTROY, ret, NULL);

DB_TEST_RECOVERY_LABEL

	return (ret);
}
jimw@mysql.com's avatar
jimw@mysql.com committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

/*
 * __db_cursor_check --
 *	See if there are any active cursors on this db.
 */
static int
__db_cursor_check(dbp)
	DB *dbp;
{
	DB *ldbp;
	DBC *dbc;
	DB_ENV *dbenv;
	int found;

	dbenv = dbp->dbenv;

jimw@mysql.com's avatar
jimw@mysql.com committed
214
	MUTEX_LOCK(dbenv, dbenv->mtx_dblist);
jimw@mysql.com's avatar
jimw@mysql.com committed
215 216 217
	for (found = 0, ldbp = __dblist_get(dbenv, dbp->adj_fileid);
	    ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
	    ldbp = LIST_NEXT(ldbp, dblistlinks)) {
jimw@mysql.com's avatar
jimw@mysql.com committed
218
		MUTEX_LOCK(dbenv, dbp->mutex);
jimw@mysql.com's avatar
jimw@mysql.com committed
219 220 221 222 223 224 225
		for (dbc = TAILQ_FIRST(&ldbp->active_queue);
		    dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
			if (IS_INITIALIZED(dbc)) {
				found = 1;
				break;
			}
		}
jimw@mysql.com's avatar
jimw@mysql.com committed
226
		MUTEX_UNLOCK(dbenv, dbp->mutex);
jimw@mysql.com's avatar
jimw@mysql.com committed
227 228 229
		if (found == 1)
			break;
	}
jimw@mysql.com's avatar
jimw@mysql.com committed
230
	MUTEX_UNLOCK(dbenv, dbenv->mtx_dblist);
jimw@mysql.com's avatar
jimw@mysql.com committed
231 232 233

	return (found);
}