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

📄 txn.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 3 页
字号:
		region->stat.st_ncommits++;	else		region->stat.st_naborts++;	--region->stat.st_nactive;	R_UNLOCK(dbenv, &mgr->reginfo);	/*	 * The transaction cannot get more locks, remove its locker info,	 * if any.	 */	if (LOCKING_ON(dbenv) && (ret =	    __lock_freefamilylocker(dbenv->lk_handle, txnp->txnid)) != 0)		return (__db_panic(dbenv, ret));	if (txnp->parent != NULL)		TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks);	/* Free the space. */	if (F_ISSET(txnp, TXN_MALLOC)) {		MUTEX_THREAD_LOCK(dbenv, mgr->mutexp);		TAILQ_REMOVE(&mgr->txn_chain, txnp, links);		MUTEX_THREAD_UNLOCK(dbenv, mgr->mutexp);		__os_free(dbenv, txnp);	}	if (do_closefiles) {		F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);		(void)__dbreg_close_files(dbenv);		F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);		mgr->n_discards = 0;		(void)dbenv->txn_checkpoint(dbenv, 0, 0, DB_FORCE);	}	return (0);}/* * __txn_undo -- *	Undo the transaction with id txnid.  Returns 0 on success and *	errno on failure. */static int__txn_undo(txnp)	DB_TXN *txnp;{	DBT rdbt;	DB_ENV *dbenv;	DB_LOGC *logc;	DB_LSN key_lsn;	DB_TXN *ptxn;	DB_TXNMGR *mgr;	int ret, t_ret;	void *txnlist;	mgr = txnp->mgrp;	dbenv = mgr->dbenv;	logc = NULL;	txnlist = NULL;	if (!DBENV_LOGGING(dbenv))		return (0);	/*	 * This is the simplest way to code this, but if the mallocs during	 * recovery turn out to be a performance issue, we can do the	 * allocation here and use DB_DBT_USERMEM.	 */	memset(&rdbt, 0, sizeof(rdbt));	key_lsn = txnp->last_lsn;	/*	 * Allocate a txnlist for children and aborted page allocs.	 * We need to associate the list with the maximal parent	 * so that aborted pages are recovered when that transaction	 * is commited or aborted.	 */	for (ptxn = txnp->parent; ptxn != NULL && ptxn->parent != NULL;)		ptxn = ptxn->parent;	if (ptxn != NULL && ptxn->txn_list != NULL)		txnlist = ptxn->txn_list;	else if (txnp->txn_list != NULL)		txnlist = txnp->txn_list;	else if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txnlist)) != 0)		return (ret);	else if (ptxn != NULL)		ptxn->txn_list = txnlist;	if (F_ISSET(txnp, TXN_CHILDCOMMIT) &&	    (ret = __db_txnlist_lsninit(dbenv, txnlist, &txnp->last_lsn)) != 0)		return (ret);	if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)		goto err;	while (ret == 0 && !IS_ZERO_LSN(key_lsn)) {		/*		 * The dispatch routine returns the lsn of the record		 * before the current one in the key_lsn argument.		 */		if ((ret = logc->get(logc, &key_lsn, &rdbt, DB_SET)) == 0) {			ret = __db_dispatch(dbenv, dbenv->recover_dtab,			    dbenv->recover_dtab_size, &rdbt, &key_lsn,			    DB_TXN_ABORT, txnlist);			if (F_ISSET(txnp, TXN_CHILDCOMMIT))				(void)__db_txnlist_lsnadd(dbenv,				    txnlist, &key_lsn, 0);		}		if (ret == DB_SURPRISE_KID) {			if ((ret = __db_txnlist_lsninit(			    dbenv, txnlist, &key_lsn)) == 0)				F_SET(txnp, TXN_CHILDCOMMIT);		} else if (ret != 0) {			__db_err(txnp->mgrp->dbenv,		    "DB_TXN->abort: Log undo failed for LSN: %lu %lu: %s",			    (u_long)key_lsn.file, (u_long)key_lsn.offset,			    db_strerror(ret));			goto err;		}	}	ret = __db_do_the_limbo(dbenv, ptxn, txnp, txnlist);err:	if (logc != NULL && (t_ret = logc->close(logc, 0)) != 0 && ret == 0)		ret = t_ret;	if (ptxn == NULL && txnlist != NULL)		__db_txnlist_end(dbenv, txnlist);	return (ret);}/* * Transaction checkpoint. * If either kbytes or minutes is non-zero, then we only take the checkpoint * more than "minutes" minutes have passed since the last checkpoint or if * more than "kbytes" of log data have been written since the last checkpoint. * When taking a checkpoint, find the oldest active transaction and figure out * its first LSN.  This is the lowest LSN we can checkpoint, since any record * written after since that point may be involved in a transaction and may * therefore need to be undone in the case of an abort. * * PUBLIC: int __txn_checkpoint * PUBLIC:     __P((DB_ENV *, u_int32_t, u_int32_t, u_int32_t)); */int__txn_checkpoint(dbenv, kbytes, minutes, flags)	DB_ENV *dbenv;	u_int32_t kbytes, minutes, flags;{	DB_LSN ckp_lsn, last_ckp;	DB_TXNMGR *mgr;	DB_TXNREGION *region;	TXN_DETAIL *txnp;	time_t last_ckp_time, now;	u_int32_t bytes, mbytes;	int ret;	PANIC_CHECK(dbenv);	ENV_REQUIRES_CONFIG(dbenv,	    dbenv->tx_handle, "txn_checkpoint", DB_INIT_TXN);	/*	 * On a replication client, all transactions are read-only;  therefore,	 * a checkpoint is a null-op.	 *	 * We permit txn_checkpoint, instead of just rendering it illegal,	 * so that an application can just let a checkpoint thread continue	 * to operate as it gets promoted or demoted between being a	 * master and a client.	 */	if (F_ISSET(dbenv, DB_ENV_REP_CLIENT))		return (0);	mgr = dbenv->tx_handle;	region = mgr->reginfo.primary;	/*	 * The checkpoint LSN is an LSN such that all transactions begun before	 * it are complete.  Our first guess (corrected below based on the list	 * of active transactions) is the last-written LSN.	 */	__log_txn_lsn(dbenv, &ckp_lsn, &mbytes, &bytes);	if (!LF_ISSET(DB_FORCE)) {		/* Don't checkpoint a quiescent database. */		if (bytes == 0 && mbytes == 0)			return (0);		if (kbytes != 0 &&		    mbytes * 1024 + bytes / 1024 >= (u_int32_t)kbytes)			goto do_ckp;		if (minutes != 0) {			(void)time(&now);			R_LOCK(dbenv, &mgr->reginfo);			last_ckp_time = region->time_ckp;			R_UNLOCK(dbenv, &mgr->reginfo);			if (now - last_ckp_time >= (time_t)(minutes * 60))				goto do_ckp;		}		/*		 * If we checked time and data and didn't go to checkpoint,		 * we're done.		 */		if (minutes != 0 || kbytes != 0)			return (0);	}do_ckp:	/* Look through the active transactions for the lowest begin LSN. */	R_LOCK(dbenv, &mgr->reginfo);	for (txnp = SH_TAILQ_FIRST(&region->active_txn, __txn_detail);	    txnp != NULL;	    txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail))		if (!IS_ZERO_LSN(txnp->begin_lsn) &&		    log_compare(&txnp->begin_lsn, &ckp_lsn) < 0)			ckp_lsn = txnp->begin_lsn;	R_UNLOCK(dbenv, &mgr->reginfo);	if (MPOOL_ON(dbenv) && (ret = dbenv->memp_sync(dbenv, NULL)) != 0) {		__db_err(dbenv,		    "txn_checkpoint: failed to flush the buffer cache %s",		    db_strerror(ret));		return (ret);	}	/*	 * Because we can't be a replication client here, and because	 * recovery (somewhat unusually) calls txn_checkpoint and expects	 * it to write a log message, LOGGING_ON is the correct macro here.	 */	if (LOGGING_ON(dbenv)) {		R_LOCK(dbenv, &mgr->reginfo);		last_ckp = region->last_ckp;		R_UNLOCK(dbenv, &mgr->reginfo);		/*		 * Put out records for the open files before we log		 * the checkpoint.  The records are certain to be at		 * or after ckp_lsn, but before the checkpoint record		 * itself, so they're sure to be included if we start		 * recovery from the ckp_lsn contained in this		 * checkpoint.		 */		if ((ret = __dbreg_open_files(dbenv)) != 0 ||		    (ret = __txn_ckp_log(dbenv,		    NULL, &ckp_lsn, DB_PERMANENT | DB_FLUSH, &ckp_lsn,		    &last_ckp, (int32_t)time(NULL))) != 0) {			__db_err(dbenv,			    "txn_checkpoint: log failed at LSN [%ld %ld] %s",			    (long)ckp_lsn.file, (long)ckp_lsn.offset,			    db_strerror(ret));			return (ret);		}		__txn_updateckp(dbenv, &ckp_lsn);	}	return (0);}/* * __txn_getckp -- *	Get the LSN of the last transaction checkpoint. * * PUBLIC: int __txn_getckp __P((DB_ENV *, DB_LSN *)); */int__txn_getckp(dbenv, lsnp)	DB_ENV *dbenv;	DB_LSN *lsnp;{	DB_LSN lsn;	DB_TXNMGR *mgr;	DB_TXNREGION *region;	mgr = dbenv->tx_handle;	region = mgr->reginfo.primary;	R_LOCK(dbenv, &mgr->reginfo);	lsn = region->last_ckp;	R_UNLOCK(dbenv, &mgr->reginfo);	if (IS_ZERO_LSN(lsn))		return (DB_NOTFOUND);	*lsnp = lsn;	return (0);}/* * __txn_activekids -- *	Return if this transaction has any active children. * * PUBLIC: int __txn_activekids __P((DB_ENV *, u_int32_t, DB_TXN *)); */int__txn_activekids(dbenv, rectype, txnp)	DB_ENV *dbenv;	u_int32_t rectype;	DB_TXN *txnp;{	/*	 * On a child commit, we know that there are children (i.e., the	 * commiting child at the least.  In that case, skip this check.	 */	if (F_ISSET(txnp, TXN_COMPENSATE) || rectype == DB___txn_child)		return (0);	if (TAILQ_FIRST(&txnp->kids) != NULL) {		__db_err(dbenv, "Child transaction is active");		return (EPERM);	}	return (0);}/* * __txn_force_abort -- *	Force an abort record into the log if the commit record *	failed to get to disk. * * PUBLIC: int __txn_force_abort __P((DB_ENV *, u_int8_t *)); */int__txn_force_abort(dbenv, buffer)	DB_ENV *dbenv;	u_int8_t *buffer;{	DB_CIPHER *db_cipher;	HDR *hdr;	u_int32_t offset, opcode, rec_len, rec_type, sum_len;	u_int8_t *bp, *key, chksum[DB_MAC_KEY];	size_t hdrsize;	int ret;	db_cipher = dbenv->crypto_handle;	/*	 * This routine depends on the layout of HDR and the __txn_regop	 * record in txn.src.  We are passed the beginning of the commit	 * record in the log buffer and overwrite the commit with an abort	 * and recalculate the checksum.  We may be passed a txn_xa_regop	 * that is, an XA prepare), there's no need to overwrite that one.	 */	hdr = (HDR *)buffer;	memcpy(&rec_type, hdr, sizeof(rec_type));	if (rec_type == DB___txn_xa_regop)		return (0);	offset = sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(DB_LSN);	rec_len = offset + sizeof(u_int32_t) + sizeof(int32_t);	if (CRYPTO_ON(dbenv)) {		key = db_cipher->mac_key;		hdrsize = HDR_CRYPTO_SZ;		sum_len = DB_MAC_KEY;		if ((ret = db_cipher->decrypt(dbenv, db_cipher->data,		    &hdr->iv[0], buffer + hdrsize, rec_len)) != 0)			return (__db_panic(dbenv, ret));	} else {		key = NULL;		hdrsize = HDR_NORMAL_SZ;		sum_len = sizeof(u_int32_t);	}	bp = buffer + hdrsize + offset;	opcode = TXN_ABORT;	memcpy(bp, &opcode, sizeof(opcode));	if (CRYPTO_ON(dbenv) &&	    (ret = db_cipher->encrypt(dbenv,	    db_cipher->data, &hdr->iv[0], buffer + hdrsize, rec_len)) != 0)		return (__db_panic(dbenv, ret));	__db_chksum(buffer + hdrsize, rec_len, key, chksum);	memcpy(buffer + SSZ(HDR, chksum), &chksum, sum_len);	return (0);}/* * __txn_preclose *	Before we can close an environment, we need to check if we * were in the midst of taking care of restored transactions.  If * so, then we need to close the files that we opened. * * PUBLIC: int __txn_preclose __P((DB_ENV *)); */int__txn_preclose(dbenv)	DB_ENV *dbenv;{	DB_TXNMGR *mgr;	DB_TXNREGION *region;	int do_closefiles, ret;	mgr = (DB_TXNMGR *)dbenv->tx_handle;	region = mgr->reginfo.primary;	do_closefiles = 0;	R_LOCK(dbenv, &mgr->reginfo);	if (region != NULL &&	    region->stat.st_nrestores	    <= mgr->n_discards && mgr->n_discards != 0)		do_closefiles = 1;	R_UNLOCK(dbenv, &mgr->reginfo);	if (do_closefiles) {		/*		 * Set the DBLOG_RECOVER flag while closing these		 * files so they do not create additional log records		 * that will confuse future recoveries.		 */		F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);		ret = __dbreg_close_files(dbenv);		F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);	} else		ret = 0;	return (ret);}/* * __txn_reset -- *	Reset the last txnid to its minimum value, and log the reset. * * PUBLIC: int __txn_reset __P((DB_ENV *)); */int__txn_reset(dbenv)	DB_ENV *dbenv;{	DB_LSN scrap;	DB_TXNREGION *region;	region = ((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary;	region->last_txnid = TXN_MINIMUM;	DB_ASSERT(LOGGING_ON(dbenv));	return (__txn_recycle_log(dbenv,	    NULL, &scrap, 0, TXN_MINIMUM, TXN_MAXIMUM));}/* * __txn_updateckp -- *	Update the last_ckp field in the transaction region.  This happens * at the end of a normal checkpoint and also when a replication client * receives a checkpoint record. * * PUBLIC: void __txn_updateckp __P((DB_ENV *, DB_LSN *)); */void__txn_updateckp(dbenv, lsnp)	DB_ENV *dbenv;	DB_LSN *lsnp;{	DB_TXNMGR *mgr;	DB_TXNREGION *region;	mgr = dbenv->tx_handle;	region = mgr->reginfo.primary;	/*	 * We want to make sure last_ckp only moves forward;  since	 * we drop locks above and in log_put, it's possible	 * for two calls to __txn_ckp_log to finish in a different	 * order from how they were called.	 */	R_LOCK(dbenv, &mgr->reginfo);	if (log_compare(&region->last_ckp, lsnp) < 0) {		region->last_ckp = *lsnp;		(void)time(&region->time_ckp);	}	R_UNLOCK(dbenv, &mgr->reginfo);}

⌨️ 快捷键说明

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