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

📄 db_dispatch.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
	DB_TXN *txn;	DB_TXNLIST *elp;	db_limbo_state state;{	DB *dbp;	DB_MPOOLFILE *mpf;	DBMETA *meta;	DB_TXN *ctxn, *t;	FNAME *fname;	db_pgno_t last_pgno, pgno;	int dbp_created, in_retry, ret, t_ret;	ctxn = NULL;	in_retry = 0;	meta = NULL;	mpf = NULL;	ret = 0;	for (; elp != NULL; elp = LIST_NEXT(elp, links)) {		if (elp->type != TXNLIST_PGNO)			continue;retry:		dbp_created = 0;		/*		 * Pick the transaction in which to potentially		 * log compensations.		 */		if (state == LIMBO_PREPARE)			ctxn = txn;		else if (!in_retry && state != LIMBO_RECOVER &&		    state != LIMBO_TIMESTAMP && !T_RESTORED(txn) &&		    (ret = __txn_compensate_begin(dbenv, &ctxn)) != 0)			return (ret);		/*		 * Either use the compensating transaction or		 * the one passed in, which will be null if recovering.		 */		t = ctxn == NULL ? txn : ctxn;		/* First try to get a dbp by fileid. */		ret = __dbreg_id_to_db(dbenv, t, &dbp, elp->u.p.fileid, 0);		/*		 * If the file was closed and reopened its id could change.		 * Look it up the hard way.		 */		if (ret == DB_DELETED || ret == ENOENT ||		    ((ret == 0 &&		    memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) != 0))) {			if ((ret = __dbreg_fid_to_fname(			    dbenv->lg_handle, elp->u.p.uid, 0, &fname)) == 0)				ret = __dbreg_id_to_db(				     dbenv, t, &dbp, fname->id, 0);		}		/*		 * File is being destroyed.  No need to worry about		 * dealing with recovery of allocations.		 */		if (ret == DB_DELETED ||		    (ret == 0 && F_ISSET(dbp, DB_AM_DISCARD)))			goto next;		if (ret != 0) {			if ((ret = db_create(&dbp, dbenv, 0)) != 0)				goto err;			/*			 * This tells the system not to lock, which is always			 * OK, whether this is an abort or recovery.			 */			F_SET(dbp, DB_AM_COMPENSATE);			dbp_created = 1;			/* It is ok if the file is nolonger there. */			ret = __db_open(dbp,			    t, elp->u.p.fname, NULL, DB_UNKNOWN,			    DB_ODDFILESIZE, __db_omode("rw----"), PGNO_BASE_MD);			if (ret == ENOENT)				goto next;		}		/*		 * Verify that we are opening the same file that we were		 * referring to when we wrote this log record.		 */		if (memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) != 0)			goto next;		mpf = dbp->mpf;		last_pgno = PGNO_INVALID;		if (meta == NULL && 		    (ctxn == NULL || state == LIMBO_COMPENSATE)) {			pgno = PGNO_BASE_MD;			if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0)				goto err;			last_pgno = meta->free;		}		if (state == LIMBO_PREPARE) {			if ((ret = __db_limbo_prepare(dbp, ctxn, elp)) != 0)				goto err;		} else			ret = __db_limbo_fix(dbp,			     ctxn, elp, &last_pgno, meta, state);		/*		 * If we were doing compensating transactions, then we are		 * going to hope this error was due to running out of space.		 * We'll change modes (into the sync the file mode) and keep		 * trying.  If we weren't doing compensating transactions,		 * then this is a real error and we're sunk.		 */		if (ret != 0) {			if (ret == DB_RUNRECOVERY || ctxn == NULL)				goto err;			in_retry = 1;			if ((ret = __txn_abort(ctxn)) != 0)				goto err;			ctxn = NULL;			goto retry;		}		if (state == LIMBO_PREPARE)			ctxn = NULL;		else if (ctxn != NULL) {			/*			 * We only force compensation at the end of recovery.			 * We want the txn_commit to be logged so turn			 * off the recovery flag briefly.			 */			if (state == LIMBO_COMPENSATE)				F_CLR(				    (DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);			ret = __txn_commit(ctxn, DB_TXN_NOSYNC);			ctxn = NULL;			if (state == LIMBO_COMPENSATE)				F_SET(				    (DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);			if (ret != 0)				goto retry;		}		/*		 * This is where we handle the case where we're explicitly		 * putting together a free list.  We need to decide whether		 * we have to write the meta-data page, and if we do, then		 * we need to sync it as well.		 */		else if (last_pgno == meta->free) {			/* No change to page; just put the page back. */			if ((ret = __memp_fput(mpf, meta, 0)) != 0)				goto err;			meta = NULL;		} else {			/*			 * These changes are unlogged so we cannot have the			 * metapage pointing at pages that are not on disk.			 * Therefore, we flush the new free list, then update			 * the metapage.  We have to put the meta-data page			 * first so that it isn't pinned when we try to sync.			 */			if (!IS_RECOVERING(dbenv) && !T_RESTORED(txn))				__db_err(dbenv, "Flushing free list to disk");			if ((ret = __memp_fput(mpf, meta, 0)) != 0)				goto err;			meta = NULL;			/*			 * If the sync fails then we cannot flush the			 * newly allocated pages.  That is, the file			 * cannot be extended. Don't let the metapage			 * point at them.			 * We may lose these pages from the file if it			 * can be extended later.  If there is never			 * space for the pages, then things will be ok.			 */			if ((ret = __db_sync(dbp)) == 0) {				pgno = PGNO_BASE_MD;				if ((ret =				    __memp_fget(mpf, &pgno, 0, &meta)) != 0)					goto err;				meta->free = last_pgno;				if ((ret = __memp_fput(mpf,				     meta, DB_MPOOL_DIRTY)) != 0)					goto err;				meta = NULL;			} else {				__db_err(dbenv,				    "%s: %s", dbp->fname, db_strerror(ret));				__db_err(dbenv, "%s: %s %s", dbp->fname,				    "allocation flush failed, some free pages",				    "may not appear in the free list");				ret = 0;			}		}next:		/*		 * If we get here, either we have processed the list		 * or the db file has been deleted or could not be opened.		 */		if (ctxn != NULL &&		    (t_ret = __txn_abort(ctxn)) != 0 && ret == 0)			ret = t_ret;		if (dbp_created &&		    (t_ret = __db_close(dbp, txn, DB_NOSYNC)) != 0 && ret == 0)			ret = t_ret;		dbp = NULL;		if (state != LIMBO_PREPARE && state != LIMBO_TIMESTAMP) {			__os_free(dbenv, elp->u.p.fname);			__os_free(dbenv, elp->u.p.pgno_array);		}		if (ret == ENOENT)			ret = 0;		else if (ret != 0)			goto err;	}err:	if (meta != NULL)		(void)__memp_fput(mpf, meta, 0);	return (ret);}/* * __db_limbo_fix -- *	Process a single limbo entry which describes all the page allocations * for a single file. */static int__db_limbo_fix(dbp, ctxn, elp, lastp, meta, state)	DB *dbp;	DB_TXN *ctxn;	DB_TXNLIST *elp;	db_pgno_t *lastp;	DBMETA *meta;	db_limbo_state state;{	DBC *dbc;	DBT ldbt;	DB_MPOOLFILE *mpf;	PAGE *freep, *pagep;	db_pgno_t next, pgno;	u_int32_t i;	int ret, t_ret;	/*	 * Loop through the entries for this txnlist element and	 * either link them into the free list or write a compensating	 * record for each.	 */	dbc = NULL;	mpf = dbp->mpf;	pagep = NULL;	ret = 0;	for (i = 0; i < elp->u.p.nentries; i++) {		pgno = elp->u.p.pgno_array[i];		if (pgno == PGNO_INVALID)			continue;		if ((ret =		    __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {			if (ret != ENOSPC)				goto err;			continue;		}		if (state == LIMBO_COMPENSATE || IS_ZERO_LSN(LSN(pagep))) {			if (ctxn == NULL) {				/*				 * If this is a fatal recovery which				 * spans a previous crash this page may				 * be on the free list already.				 */				for (next = *lastp; next != 0; ) {					if (next == pgno)						break;					if ((ret = __memp_fget(mpf,					    &next, 0, &freep)) != 0)						goto err;					next = NEXT_PGNO(freep);					if ((ret =					    __memp_fput(mpf, freep, 0)) != 0)						goto err;				}				if (next != pgno) {					P_INIT(pagep, dbp->pgsize, pgno,					    PGNO_INVALID, *lastp, 0, P_INVALID);					/* Make the lsn non-zero but generic. */					INIT_LSN(LSN(pagep));					*lastp = pgno;				}			} else if (state == LIMBO_COMPENSATE) {				/*				 * Generate a log record for what we did on the				 * LIMBO_TIMESTAMP pass.  All pages here are				 * free so P_OVERHEAD is sufficient.				 */				ZERO_LSN(pagep->lsn);				memset(&ldbt, 0, sizeof(ldbt));				ldbt.data = pagep;				ldbt.size = P_OVERHEAD(dbp);				if ((ret = __db_pg_new_log(dbp, ctxn,				     &LSN(meta), 0, pagep->pgno,				     &LSN(meta), PGNO_BASE_MD,				     &ldbt, pagep->next_pgno)) != 0)					goto err;			} else {				if (dbc == NULL && (ret =				    __db_cursor(dbp, ctxn, &dbc, 0)) != 0)						goto err;				/*				 * If the dbp is compensating (because we				 * opened it), the dbc will automatically be				 * marked compensating, but in case we didn't				 * do the open, we have to mark it explicitly.				 */				F_SET(dbc, DBC_COMPENSATE);				ret = __db_free(dbc, pagep);				pagep = NULL;				/*				 * On any error, we hope that the error was				 * caused due to running out of space, and we				 * switch modes, doing the processing where we				 * sync out files instead of doing compensating				 * transactions.  If this was a real error and				 * not out of space, we assume that some other				 * call will fail real soon.				 */				if (ret != 0) {					/* Assume that this is out of space. */					(void)__db_c_close(dbc);					dbc = NULL;					goto err;				}			}		}		else			elp->u.p.pgno_array[i] = PGNO_INVALID;		if (pagep != NULL) {			ret = __memp_fput(mpf, pagep, DB_MPOOL_DIRTY);			pagep = NULL;		}		if (ret != 0)			goto err;	}err:	if (pagep != NULL &&	    (t_ret = __memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)		ret = t_ret;	if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0)		ret = t_ret;	return (ret);}static int__db_limbo_prepare(dbp, txn, elp)	DB *dbp;	DB_TXN *txn;	DB_TXNLIST *elp;{	DB_LSN lsn;	DB_MPOOLFILE *mpf;	PAGE *pagep;	db_pgno_t pgno;	u_int32_t i;	int ret, t_ret;	/*	 * Loop through the entries for this txnlist element and	 * output a prepare record for them.	 */	pagep = NULL;	ret = 0;	mpf = dbp->mpf;	for (i = 0; i < elp->u.p.nentries; i++) {		pgno = elp->u.p.pgno_array[i];		if ((ret =		    __memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {			if (ret != ENOSPC)				return (ret);			continue;		}		if (IS_ZERO_LSN(LSN(pagep)))			ret = __db_pg_prepare_log(dbp, txn, &lsn, 0, pgno);		if ((t_ret = __memp_fput(mpf, pagep, 0)) != 0 && ret == 0)			ret = t_ret;		if (ret != 0)			return (ret);	}	return (0);}#define	DB_TXNLIST_MAX_PGNO	8		/* A nice even number. *//* * __db_txnlist_pgnoadd -- *	Find the txnlist entry for a file and add this pgno, or add the list *	entry for the file and then add the pgno. */static int__db_txnlist_pgnoadd(dbenv, hp, fileid, uid, fname, pgno)	DB_ENV *dbenv;	DB_TXNHEAD *hp;	int32_t fileid;	u_int8_t uid[DB_FILE_ID_LEN];	char *fname;	db_pgno_t pgno;{	DB_TXNLIST *elp;	size_t len;	u_int32_t hash, status;	int ret;	elp = NULL;	if ((ret = __db_txnlist_find_internal(dbenv, hp,	    TXNLIST_PGNO, 0, uid, &elp, 0, &status)) != 0 && ret != DB_NOTFOUND)		goto err;	if (ret == DB_NOTFOUND || status != TXN_OK) {		if ((ret =		    __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0)			goto err;		memcpy(&hash, uid, sizeof(hash));		LIST_INSERT_HEAD(		    &hp->head[DB_TXNLIST_MASK(hp, hash)], elp, links);		memcpy(elp->u.p.uid, uid, DB_FILE_ID_LEN);		len = strlen(fname) + 1;		if ((ret = __os_malloc(dbenv, len, &elp->u.p.fname)) != 0)			goto err;		memcpy(elp->u.p.fname, fname, len);		elp->u.p.maxentry = 0;		elp->u.p.locked = 0;		elp->type = TXNLIST_PGNO;		if ((ret = __os_malloc(dbenv,		    8 * sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0)			goto err;		elp->u.p.maxentry = DB_TXNLIST_MAX_PGNO;		elp->u.p.nentries = 0;	} else if (elp->u.p.nentries == elp->u.p.maxentry) {		elp->u.p.maxentry <<= 1;		if ((ret = __os_realloc(dbenv, elp->u.p.maxentry *		    sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0)			goto err;	}	elp->u.p.pgno_array[elp->u.p.nentries++] = pgno;	/* Update to the latest fileid.  Limbo will find it faster. */	elp->u.p.fileid = fileid;	return (0);err:	return (ret);}#endif#ifdef DEBUG/* * __db_txnlist_print -- *	Print out the transaction list. * * PUBLIC: void __db_txnlist_print __P((void *)); */void__db_txnlist_print(listp)	void *listp;{	DB_TXNHEAD *hp;	DB_TXNLIST *p;	u_int32_t i;	char *txntype;	hp = (DB_TXNHEAD *)listp;	printf("Maxid: %lu Generation: %lu\n",	    (u_long)hp->maxid, (u_long)hp->generation);	for (i = 0; i < hp->nslots; i++)		for (p = LIST_FIRST(&hp->head[i]);		    p != NULL; p = LIST_NEXT(p, links)) {			if (p->type != TXNLIST_TXNID) {				printf("Unrecognized type: %d\n", p->type);				continue;			}			switch (p->u.t.status) {			case TXN_OK:				txntype = "OK";				break;			case TXN_COMMIT:				txntype = "commit";				break;			case TXN_PREPARE:				txntype = "prepare";				break;			case TXN_ABORT:				txntype = "abort";				break;			case TXN_IGNORE:				txntype = "ignore";				break;			case TXN_EXPECTED:				txntype = "expected";				break;			case TXN_UNEXPECTED:				txntype = "unexpected";				break;			default:				txntype = "UNKNOWN";				break;			}			printf("TXNID: %lx(%lu): %s\n",			    (u_long)p->u.t.txnid,			    (u_long)p->u.t.generation, txntype);		}}#endif

⌨️ 快捷键说明

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