⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 txn.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 3 页
字号:
		F_CLR(txnp, TXN_SYNC);		F_SET(txnp, TXN_NOSYNC);	}	if (LF_ISSET(DB_TXN_SYNC)) {		F_CLR(txnp, TXN_NOSYNC);		F_SET(txnp, TXN_SYNC);	}	/*	 * Commit any unresolved children.  If anyone fails to commit,	 * then try to abort the rest of the kids and then abort the parent.	 * Abort should never fail; if it does, we bail out immediately.	 */	while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL)		if ((ret = kid->commit(kid, flags)) != 0)			while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL)				if ((t_ret = kid->abort(kid)) != 0)					return (__db_panic(dbenv, t_ret));	/*	 * Process any aborted pages from our children.	 * We delay putting pages on the free list that are newly	 * allocated and then aborted so that we can undo other	 * allocations, if necessary, without worrying about	 * these pages which were not on the free list before.	 */	if (txnp->txn_list != NULL) {		t_ret = __db_do_the_limbo(dbenv, NULL, txnp, txnp->txn_list);		__db_txnlist_end(dbenv, txnp->txn_list);		txnp->txn_list = NULL;		if (t_ret != 0 && ret == 0)			ret = t_ret;	}	if (ret != 0)		goto err;	/*	 * If there are any log records, write a log record and sync the log,	 * else do no log writes.  If the commit is for a child transaction,	 * we do not need to commit the child synchronously since it may still	 * abort (if its parent aborts), and otherwise its parent or ultimate	 * ancestor will write synchronously.	 */	if (DBENV_LOGGING(dbenv) && !IS_ZERO_LSN(txnp->last_lsn)) {		if (txnp->parent == NULL) {			/*			 * We are about to free all the read locks			 * for this transaction below.  Some of those			 * locks might be handle locks which should			 * not be freed, because they will be freed			 * when the handle is closed.  Check the			 * events and preprocess any trades now so			 * that we don't release the locks below.			 */			if ((ret = __txn_doevents(dbenv, txnp, 0, 1)) != 0)				goto err;			request.op = DB_LOCK_PUT_READ;			if (LOCKING_ON(dbenv) && (ret = dbenv->lock_vec(			   dbenv, txnp->txnid, 0, &request, 1, NULL)) != 0)				goto err;			SET_LOG_FLAGS(dbenv, txnp, lflags);			if ((ret = __txn_regop_log(dbenv,			    txnp, &txnp->last_lsn, lflags,			    TXN_COMMIT, (int32_t)time(NULL))) != 0)				goto err;		} else {			/* Log the commit in the parent! */			if ((ret = __txn_child_log(dbenv,			    txnp->parent, &txnp->parent->last_lsn,			    0, txnp->txnid, &txnp->last_lsn)) != 0) {				goto err;			}			F_SET(txnp->parent, TXN_CHILDCOMMIT);		}	}	/* This is OK because __txn_end can only fail with a panic. */	return (__txn_end(txnp, 1));err:	/*	 * If we are prepared, then we "must" be able to commit.  We	 * panic here because even though the coordinator might be	 * able to retry it is not clear it would know to do that.	 * Otherwise  we'll try to abort.  If that is successful,	 * then we return whatever was in ret (i.e., the reason we failed).	 * If the abort was unsuccessful, then abort probably returned	 * DB_RUNRECOVERY and we need to propagate that up.	 */	if (td->status == TXN_PREPARED)		return (__db_panic(dbenv, ret));			if ((t_ret = txnp->abort(txnp)) != 0)		ret = t_ret;	return (ret);}/* * __txn_abort -- *	Abort a transaction. * * PUBLIC: int __txn_abort __P((DB_TXN *)); */int__txn_abort(txnp)	DB_TXN *txnp;{	DB_ENV *dbenv;	DB_LOCKREQ request;	DB_TXN *kid;	TXN_DETAIL *td;	u_int32_t lflags;	int ret;	dbenv = txnp->mgrp->dbenv;	PANIC_CHECK(dbenv);	/* Ensure that abort always fails fatally. */	if ((ret = __txn_isvalid(txnp, &td, TXN_OP_ABORT)) != 0)		return (__db_panic(dbenv, ret));	/*	 * Try to abort any unresolved children.	 *	 * Abort either succeeds or panics the region.  As soon as we	 * see any failure, we just get out of here and return the panic	 * up.	 */	while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL)		if ((ret = kid->abort(kid)) != 0)			return (ret);	if (LOCKING_ON(dbenv)) {		/*		 * We are about to free all the read locks for this transaction		 * below.  Some of those locks might be handle locks which		 * should not be freed, because they will be freed when the		 * handle is closed.  Check the events and preprocess any		 * trades now so that we don't release the locks below.		 */		if ((ret = __txn_doevents(dbenv, txnp, 0, 1)) != 0)			return (__db_panic(dbenv, ret));		/* Turn off timeouts. */		if ((ret = __lock_set_timeout(dbenv,		    txnp->txnid, 0, DB_SET_TXN_TIMEOUT)) != 0)			return (__db_panic(dbenv, ret));		if ((ret = __lock_set_timeout(dbenv,		    txnp->txnid, 0, DB_SET_LOCK_TIMEOUT)) != 0)			return (__db_panic(dbenv, ret));		request.op = DB_LOCK_UPGRADE_WRITE;		if ((ret = dbenv->lock_vec(		    dbenv, txnp->txnid, 0, &request, 1, NULL)) != 0)			return (__db_panic(dbenv, ret));	}	if ((ret = __txn_undo(txnp)) != 0)		return (__db_panic(dbenv, ret));	/*	 * Normally, we do not need to log aborts.  However, if we	 * are a distributed transaction (i.e., we have a prepare),	 * then we log the abort so we know that this transaction	 * was actually completed.	 */	SET_LOG_FLAGS(dbenv, txnp, lflags);	if (DBENV_LOGGING(dbenv) && td->status == TXN_PREPARED &&	    (ret = __txn_regop_log(dbenv, txnp, &txnp->last_lsn,	    lflags, TXN_ABORT, (int32_t)time(NULL))) != 0)		return (__db_panic(dbenv, ret));	/* __txn_end always panics if it errors, so pass the return along. */	return (__txn_end(txnp, 0));}/* * __txn_discard -- *	Free the per-process resources associated with this txn handle. * * PUBLIC: int __txn_discard __P((DB_TXN *, u_int32_t flags)); */int__txn_discard(txnp, flags)	DB_TXN *txnp;	u_int32_t flags;{	DB_ENV *dbenv;	DB_TXN *freep;	TXN_DETAIL *td;	int ret;	COMPQUIET(flags, 0);	dbenv = txnp->mgrp->dbenv;	freep = NULL;	PANIC_CHECK(dbenv);	if ((ret = __txn_isvalid(txnp, &td, TXN_OP_DISCARD)) != 0)		return (ret);	/* Should be no children. */	DB_ASSERT(TAILQ_FIRST(&txnp->kids) == NULL);	DB_ASSERT(F_ISSET(td, TXN_RESTORED));	/* Free the space. */	MUTEX_THREAD_LOCK(dbenv, txnp->mgrp->mutexp);	txnp->mgrp->n_discards++;	if (F_ISSET(txnp, TXN_MALLOC)) {		TAILQ_REMOVE(&txnp->mgrp->txn_chain, txnp, links);		freep = txnp;	}	MUTEX_THREAD_UNLOCK(dbenv, txnp->mgrp->mutexp);	if (freep != NULL)		__os_free(dbenv, freep);	return (0);}/* * __txn_prepare -- *	Flush the log so a future commit is guaranteed to succeed. * * PUBLIC: int __txn_prepare __P((DB_TXN *, u_int8_t *)); */int__txn_prepare(txnp, gid)	DB_TXN *txnp;	u_int8_t *gid;{	DBT xid;	DB_ENV *dbenv;	DB_TXN *kid;	TXN_DETAIL *td;	u_int32_t lflags;	int ret;	dbenv = txnp->mgrp->dbenv;	PANIC_CHECK(dbenv);	if ((ret = __txn_isvalid(txnp, &td, TXN_OP_PREPARE)) != 0)		return (ret);	/* Commit any unresolved children. */	while ((kid = TAILQ_FIRST(&txnp->kids)) != NULL)		if ((ret = kid->commit(kid, DB_TXN_NOSYNC)) != 0)			return (ret);	/*	 * In XA, the global transaction ID in the txn_detail structure is	 * already set; in a non-XA environment, we must set it here.  XA	 * requires that the transaction be either ENDED or SUSPENDED when	 * prepare is called, so we know that if the xa_status isn't in one	 * of those states, then we are calling prepare directly and we need	 * to fill in the td->xid.	 */	if (DBENV_LOGGING(dbenv)) {		memset(&xid, 0, sizeof(xid));		if (td->xa_status != TXN_XA_ENDED &&		    td->xa_status != TXN_XA_SUSPENDED)			/* Regular prepare; fill in the gid. */			memcpy(td->xid, gid, sizeof(td->xid));		xid.size = sizeof(td->xid);		xid.data = td->xid;		SET_LOG_FLAGS(dbenv, txnp, lflags);		if ((ret = __txn_xa_regop_log(dbenv, txnp, &txnp->last_lsn,		    lflags, TXN_PREPARE, &xid, td->format, td->gtrid, td->bqual,		    &td->begin_lsn)) != 0) {			__db_err(dbenv, "DB_TXN->prepare: log_write failed %s",			    db_strerror(ret));			return (ret);		}	}	MUTEX_THREAD_LOCK(dbenv, txnp->mgrp->mutexp);	td->status = TXN_PREPARED;	MUTEX_THREAD_UNLOCK(dbenv, txnp->mgrp->mutexp);	return (0);}/* * __txn_id -- *	Return the transaction ID. * * PUBLIC: u_int32_t __txn_id __P((DB_TXN *)); */u_int32_t__txn_id(txnp)	DB_TXN *txnp;{	return (txnp->txnid);}/* * __txn_set_timeout -- *	Set timeout values in the txn structure. */static int__txn_set_timeout(txnp, timeout, op)	DB_TXN *txnp;	db_timeout_t timeout;	u_int32_t op;{	if (op != DB_SET_TXN_TIMEOUT &&  op != DB_SET_LOCK_TIMEOUT)		return (__db_ferr(txnp->mgrp->dbenv, "DB_TXN->set_timeout", 0));	return (__lock_set_timeout(	    txnp->mgrp->dbenv, txnp->txnid, timeout, op));}/* * __txn_isvalid -- *	Return 0 if the txnp is reasonable, otherwise panic. */static int__txn_isvalid(txnp, tdp, op)	const DB_TXN *txnp;	TXN_DETAIL **tdp;	txnop_t op;{	DB_TXNMGR *mgrp;	DB_TXNREGION *region;	TXN_DETAIL *tp;	mgrp = txnp->mgrp;	region = mgrp->reginfo.primary;	/* Check for recovery. */	if (!F_ISSET(txnp, TXN_COMPENSATE) &&	    F_ISSET(region, TXN_IN_RECOVERY)) {		__db_err(mgrp->dbenv,		    "operation not permitted during recovery");		goto err;	}	/* Check for live cursors. */	if (txnp->cursors != 0) {		__db_err(mgrp->dbenv, "transaction has active cursors");		goto err;	}	/* Check transaction's state. */	tp = (TXN_DETAIL *)R_ADDR(&mgrp->reginfo, txnp->off);	if (tdp != NULL)		*tdp = tp;	/* Handle any operation specific checks. */	switch (op) {	case TXN_OP_DISCARD:		/*		 * Since we're just tossing the per-process space; there are		 * a lot of problems with the transaction that we can tolerate.		 */		/* Transaction is already been reused. */		if (txnp->txnid != tp->txnid)			return (0);		/* What we've got had better be a restored transaction. */		if (!F_ISSET(tp, TXN_RESTORED)) {			__db_err(mgrp->dbenv, "not a restored transaction");			return (__db_panic(mgrp->dbenv, EINVAL));		}		return (0);	case TXN_OP_PREPARE:		if (txnp->parent != NULL) {			/*			 * This is not fatal, because you could imagine an			 * application that simply prepares everybody because			 * it doesn't distinguish between children and parents.			 * I'm not arguing this is good, but I could imagine			 * someone doing it.			 */			__db_err(mgrp->dbenv,			    "Prepare disallowed on child transactions");			return (EINVAL);		}		break;	case TXN_OP_ABORT:	case TXN_OP_COMMIT:	default:		break;	}	switch (tp->status) {	case TXN_PREPARED:		if (op == TXN_OP_PREPARE) {			__db_err(mgrp->dbenv, "transaction already prepared");			/*			 * Txn_prepare doesn't blow away the user handle, so			 * in this case, give the user the opportunity to			 * abort or commit.			 */			return (EINVAL);		}		break;	case TXN_RUNNING:		break;	case TXN_ABORTED:	case TXN_COMMITTED:	default:		__db_err(mgrp->dbenv, "transaction already %s",		    tp->status == TXN_COMMITTED ? "committed" : "aborted");		goto err;	}	return (0);err:	/*	 * If there's a serious problem with the transaction, panic.  TXN	 * handles are dead by definition when we return, and if you use	 * a cursor you forgot to close, we have no idea what will happen.	 */	return (__db_panic(mgrp->dbenv, EINVAL));}/* * __txn_end -- *	Internal transaction end routine. */static int__txn_end(txnp, is_commit)	DB_TXN *txnp;	int is_commit;{	DB_ENV *dbenv;	DB_LOCKREQ request;	DB_TXNMGR *mgr;	DB_TXNREGION *region;	TXN_DETAIL *tp;	int do_closefiles, ret;	mgr = txnp->mgrp;	dbenv = mgr->dbenv;	region = mgr->reginfo.primary;	do_closefiles = 0;	/* Process commit events. */	if ((ret = __txn_doevents(dbenv, txnp, is_commit, 0)) != 0)		return (__db_panic(dbenv, ret));	/* Release the locks. */	request.op = txnp->parent == NULL ||	    is_commit == 0 ? DB_LOCK_PUT_ALL : DB_LOCK_INHERIT;	/*	 * __txn_end cannot return an simple error, we MUST return	 * success/failure from commit or abort, ignoring any internal	 * errors.  So, we panic if something goes wrong.  We can't	 * deadlock here because we're not acquiring any new locks,	 * so DB_LOCK_DEADLOCK is just as fatal as any other error.	 */	if (LOCKING_ON(dbenv) && (ret = dbenv->lock_vec(	    dbenv, txnp->txnid, DB_LOCK_FREE_LOCKER, &request, 1, NULL)) != 0)		return (__db_panic(dbenv, ret));	/* End the transaction. */	R_LOCK(dbenv, &mgr->reginfo);	tp = (TXN_DETAIL *)R_ADDR(&mgr->reginfo, txnp->off);	SH_TAILQ_REMOVE(&region->active_txn, tp, links, __txn_detail);	if (F_ISSET(tp, TXN_RESTORED)) {		region->stat.st_nrestores--;		do_closefiles = region->stat.st_nrestores == 0;	}	__db_shalloc_free(mgr->reginfo.addr, tp);	if (is_commit)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -