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

📄 db_dispatch.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 3 页
字号:
{	DB_TXNHEAD *hp;	COMPQUIET(dbenv, NULL);	hp = (DB_TXNHEAD *)listp;	if (IS_ZERO_LSN(hp->ckplsn) && !IS_ZERO_LSN(hp->maxlsn) &&	    log_compare(&hp->maxlsn, ckp_lsn) >= 0)		hp->ckplsn = *ckp_lsn;}/* * __db_txnlist_end -- *	Discard transaction linked list. Print out any error messages * for deleted files. * * PUBLIC: void __db_txnlist_end __P((DB_ENV *, void *)); */void__db_txnlist_end(dbenv, listp)	DB_ENV *dbenv;	void *listp;{	DB_TXNHEAD *hp;	DB_TXNLIST *p;	int i;	if ((hp = (DB_TXNHEAD *)listp) == NULL)		return;	for (i = 0; i < hp->nslots; i++)		while (hp != NULL && (p = LIST_FIRST(&hp->head[i])) != NULL) {			LIST_REMOVE(p, links);			switch (p->type) {			case TXNLIST_LSN:				__os_free(dbenv, p->u.l.lsn_array);				break;			default:				/*				 * Possibly an incomplete DB_TXNLIST; just				 * free it.				 */				break;			}			__os_free(dbenv, p);		}	if (hp->gen_array != NULL)		__os_free(dbenv, hp->gen_array);	__os_free(dbenv, listp);}/* * __db_txnlist_find -- *	Checks to see if a txnid with the current generation is in the *	txnid list.  This returns TXN_NOTFOUND if the item isn't in the *	list otherwise it returns (like __db_txnlist_find_internal) *	the status of the transaction.  A txnid of 0 means the record *	was generated while not in a transaction. * * PUBLIC: int __db_txnlist_find __P((DB_ENV *, void *, u_int32_t)); */int__db_txnlist_find(dbenv, listp, txnid)	DB_ENV *dbenv;	void *listp;	u_int32_t txnid;{	DB_TXNLIST *entry;	if (txnid == 0)		return (TXN_NOTFOUND);	return (__db_txnlist_find_internal(dbenv, listp,	    TXNLIST_TXNID, txnid, NULL, &entry, 0));}/* * __db_txnlist_update -- *	Change the status of an existing transaction entry. *	Returns TXN_NOTFOUND if no such entry exists. * * PUBLIC: int __db_txnlist_update __P((DB_ENV *, * PUBLIC:     void *, u_int32_t, u_int32_t, DB_LSN *)); */int__db_txnlist_update(dbenv, listp, txnid, status, lsn)	DB_ENV *dbenv;	void *listp;	u_int32_t txnid;	u_int32_t status;	DB_LSN *lsn;{	DB_TXNHEAD *hp;	DB_TXNLIST *elp;	int ret;	if (txnid == 0)		return (TXN_NOTFOUND);	hp = (DB_TXNHEAD *)listp;	ret = __db_txnlist_find_internal(dbenv,	    listp, TXNLIST_TXNID, txnid, NULL, &elp, 0);	if (ret == TXN_NOTFOUND)		return (ret);	elp->u.t.status = status;	if (lsn != NULL && IS_ZERO_LSN(hp->maxlsn) && status == TXN_COMMIT)		hp->maxlsn = *lsn;	return (ret);}/* * __db_txnlist_find_internal -- *	Find an entry on the transaction list.  If the entry is not there or *	the list pointer is not initialized we return TXN_NOTFOUND.  If the *	item is found, we return the status.  Currently we always call this *	with an initialized list pointer but checking for NULL keeps it general. */static int__db_txnlist_find_internal(dbenv, listp, type, txnid, uid, txnlistp, delete)	DB_ENV *dbenv;	void *listp;	db_txnlist_type type;	u_int32_t  txnid;	u_int8_t uid[DB_FILE_ID_LEN];	DB_TXNLIST **txnlistp;	int delete;{	DB_TXNHEAD *hp;	DB_TXNLIST *p;	int32_t generation;	u_int32_t hash;	struct __db_headlink *head;	int i, ret;	if ((hp = (DB_TXNHEAD *)listp) == NULL)		return (TXN_NOTFOUND);	switch (type) {	case TXNLIST_TXNID:		hash = txnid;		/* Find the most recent generation containing this ID */		for (i = 0; i <= hp->generation; i++)			/* The range may wrap around the end. */			if (hp->gen_array[i].txn_min <			    hp->gen_array[i].txn_max ?			    (txnid >= hp->gen_array[i].txn_min &&			    txnid <= hp->gen_array[i].txn_max) :			    (txnid >= hp->gen_array[i].txn_min ||			    txnid <= hp->gen_array[i].txn_max))				break;		DB_ASSERT(i <= hp->generation);		generation = hp->gen_array[i].generation;		break;	case TXNLIST_PGNO:		memcpy(&hash, uid, sizeof(hash));		generation = 0;		break;	default:		DB_ASSERT(0);		return (EINVAL);	}	head = &hp->head[DB_TXNLIST_MASK(hp, hash)];	for (p = LIST_FIRST(head); p != NULL; p = LIST_NEXT(p, links)) {		if (p->type != type)			continue;		switch (type) {		case TXNLIST_TXNID:			if (p->u.t.txnid != txnid ||			    generation != p->u.t.generation)				continue;			ret = p->u.t.status;			break;		case TXNLIST_PGNO:			if (memcmp(uid, p->u.p.uid, DB_FILE_ID_LEN) != 0)				continue;			ret = 0;			break;		default:			DB_ASSERT(0);			ret = EINVAL;		}		if (delete == 1) {			LIST_REMOVE(p, links);			__os_free(dbenv, p);		} else if (p != LIST_FIRST(head)) {			/* Move it to head of list. */			LIST_REMOVE(p, links);			LIST_INSERT_HEAD(head, p, links);		}		*txnlistp = p;		return (ret);	}	return (TXN_NOTFOUND);}/* * __db_txnlist_gen -- *	Change the current generation number. * * PUBLIC: int __db_txnlist_gen __P((DB_ENV *, * PUBLIC:       void *, int, u_int32_t, u_int32_t)); */int__db_txnlist_gen(dbenv, listp, incr, min, max)	DB_ENV *dbenv;	void *listp;	int incr;	u_int32_t min, max;{	DB_TXNHEAD *hp;	int ret;	/*	 * During recovery generation numbers keep track of "restart"	 * checkpoints and recycle records.  Restart checkpoints occur	 * whenever we take a checkpoint and there are no outstanding	 * transactions.  When that happens, we can reset transaction IDs	 * back to TXNID_MINIMUM.  Currently we only do the reset	 * at then end of recovery.  Recycle records occrur when txnids	 * are exhausted during runtime.  A free range of ids is identified	 * and logged.  This code maintains a stack of ranges.  A txnid	 * is given the generation number of the first range it falls into	 * in the stack.	 */	hp = (DB_TXNHEAD *)listp;	hp->generation += incr;	if (incr < 0)		memmove(hp->gen_array, &hp->gen_array[1],		    (hp->generation + 1) * sizeof(hp->gen_array[0]));	else {		if (hp->generation >= hp->gen_alloc) {			hp->gen_alloc *= 2;			if ((ret = __os_realloc(dbenv, hp->gen_alloc *			    sizeof(hp->gen_array[0]), &hp->gen_array)) != 0)				return (ret);		}		memmove(&hp->gen_array[1], &hp->gen_array[0],		    hp->generation * sizeof(hp->gen_array[0]));		hp->gen_array[0].generation = hp->generation;		hp->gen_array[0].txn_min = min;		hp->gen_array[0].txn_max = max;	}	return (0);}#define	TXN_BUBBLE(AP, MAX) {						\	int __j;							\	DB_LSN __tmp;							\									\	for (__j = 0; __j < MAX - 1; __j++)				\		if (log_compare(&AP[__j], &AP[__j + 1]) < 0) {		\			__tmp = AP[__j];				\			AP[__j] = AP[__j + 1];				\			AP[__j + 1] = __tmp;				\		}							\}/* * __db_txnlist_lsnadd -- *	Add to or re-sort the transaction list lsn entry.  Note that since this *	is used during an abort, the __txn_undo code calls into the "recovery" *	subsystem explicitly, and there is only a single TXNLIST_LSN entry on *	the list. * * PUBLIC: int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t)); */int__db_txnlist_lsnadd(dbenv, listp, lsnp, flags)	DB_ENV *dbenv;	void *listp;	DB_LSN *lsnp;	u_int32_t flags;{	DB_TXNHEAD *hp;	DB_TXNLIST *elp;	int i, ret;	hp = (DB_TXNHEAD *)listp;	for (elp = LIST_FIRST(&hp->head[0]);	    elp != NULL; elp = LIST_NEXT(elp, links))		if (elp->type == TXNLIST_LSN)			break;	if (elp == NULL)		return (DB_SURPRISE_KID);	if (LF_ISSET(TXNLIST_NEW)) {		if (elp->u.l.ntxns >= elp->u.l.maxn) {			if ((ret = __os_realloc(dbenv,			    2 * elp->u.l.maxn * sizeof(DB_LSN),			    &elp->u.l.lsn_array)) != 0)				return (ret);			elp->u.l.maxn *= 2;		}		elp->u.l.lsn_array[elp->u.l.ntxns++] = *lsnp;	} else		/* Simply replace the 0th element. */		elp->u.l.lsn_array[0] = *lsnp;	/*	 * If we just added a new entry and there may be NULL entries, so we	 * have to do a complete bubble sort, not just trickle a changed entry	 * around.	 */	for (i = 0; i < (!LF_ISSET(TXNLIST_NEW) ? 1 : elp->u.l.ntxns); i++)		TXN_BUBBLE(elp->u.l.lsn_array, elp->u.l.ntxns);	*lsnp = elp->u.l.lsn_array[0];	return (0);}/* * __db_txnlist_lsninit -- *	Initialize a transaction list with an lsn array entry. * * PUBLIC: int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *)); */int__db_txnlist_lsninit(dbenv, hp, lsnp)	DB_ENV *dbenv;	DB_TXNHEAD *hp;	DB_LSN *lsnp;{	DB_TXNLIST *elp;	int ret;	elp = NULL;	if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0)		goto err;	LIST_INSERT_HEAD(&hp->head[0], elp, links);	if ((ret = __os_malloc(dbenv,	    12 * sizeof(DB_LSN), &elp->u.l.lsn_array)) != 0)		goto err;	elp->type = TXNLIST_LSN;	elp->u.l.maxn = 12;	elp->u.l.ntxns = 1;	elp->u.l.lsn_array[0] = *lsnp;	return (0);err:	__db_txnlist_end(dbenv, hp);	return (ret);}/* * __db_add_limbo -- add pages to the limbo list. *	Get the file information and call pgnoadd for each page. * * PUBLIC: int __db_add_limbo __P((DB_ENV *, * PUBLIC:      void *, int32_t, db_pgno_t, int32_t)); */int__db_add_limbo(dbenv, info, fileid, pgno, count)	DB_ENV *dbenv;	void *info;	int32_t fileid;	db_pgno_t pgno;	int32_t count;{	DB_LOG *dblp;	FNAME *fnp;	int ret;	dblp = dbenv->lg_handle;	if ((ret = __dbreg_id_to_fname(dblp, fileid, 0, &fnp)) != 0)		return (ret);	do {		if ((ret =		    __db_txnlist_pgnoadd(dbenv, info, fileid, fnp->ufid,		    R_ADDR(&dblp->reginfo, fnp->name_off), pgno)) != 0)			return (ret);		pgno++;	} while (--count != 0);	return (0);}/* * __db_do_the_limbo -- move pages from limbo to free. * * Limbo processing is what ensures that we correctly handle and * recover from page allocations.  During recovery, for each database, * we process each in-question allocation, link them into the free list * and then write out the new meta-data page that contains the pointer * to the new beginning of the free list.  On an abort, we use our * standard __db_free mechanism in a compensating transaction which logs * the specific modifications to the free list. * * If we run out of log space during an abort, then we can't write the * compensating transaction, so we abandon the idea of a compenating * transaction, and go back to processing how we do during recovery. * The reason that this is not the norm is that it's expensive: it requires * that we flush any database with an in-question allocation.  Thus if * a compensating transaction fails, we never try to restart it. * * Since files may be open and closed within transactions (in particular, * the master database for subdatabases), we must be prepared to open * files during this process.  If there is a compensating transaction, we * can open the files in that transaction.  If this was an abort and there * is no compensating transaction, then we've got to perform these opens * in the context of the aborting transaction so that we do not deadlock. * During recovery, there's no locking, so this isn't an issue. * * What you want to keep in mind when reading this is that there are two * algorithms going on here:  ctxn == NULL, then we're either in recovery * or our compensating transaction has failed and we're doing the * "create list and write meta-data page" algorithm.  Otherwise, we're in * an abort and doing the "use compensating transaction" algorithm. * * PUBLIC: int __db_do_the_limbo __P((DB_ENV *, * PUBLIC:     DB_TXN *, DB_TXN *, DB_TXNHEAD *)); */int__db_do_the_limbo(dbenv, ptxn, txn, hp)	DB_ENV *dbenv;	DB_TXN *ptxn, *txn;	DB_TXNHEAD *hp;{	DB_TXNLIST *elp;	int h, ret;	ret = 0;	/*	 * The slots correspond to hash buckets.  We've hashed the	 * fileids into hash buckets and need to pick up all affected	 * files. (There will only be a single slot for an abort.)	 */	for (h = 0; h < hp->nslots; h++) {		if ((elp = LIST_FIRST(&hp->head[h])) == NULL)			continue;		if (ptxn != NULL) {			if ((ret =			    __db_limbo_move(dbenv, ptxn, txn, elp)) != 0)				goto err;		} else if ((ret = __db_limbo_bucket(dbenv, txn, elp)) != 0)			goto err;	}err:	if (ret != 0) {		__db_err(dbenv, "Fatal error in abort of an allocation");		ret = __db_panic(dbenv, ret);	}	return (ret);}/* Limbo support routines. *//* * __db_lock_move -- *	Move a lock from child to parent. */static int__db_lock_move(dbenv, fileid, pgno, mode, ptxn, txn)	DB_ENV *dbenv;	u_int8_t *fileid;

⌨️ 快捷键说明

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