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

📄 rep_record.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
		ZERO_LSN(max_lsn);		ret = DB_REP_LOGREADY;	}	MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);	if (ret == 0 && !F_ISSET(rep, REP_F_RECOVER_LOG) &&	    !IS_ZERO_LSN(max_lsn)) {		if (ret_lsnp != NULL)			*ret_lsnp = max_lsn;		ret = DB_REP_ISPERM;		DB_ASSERT(log_compare(&max_lsn, &lp->max_perm_lsn) >= 0);		lp->max_perm_lsn = max_lsn;	}	MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);	/*	 * Startup is complete when we process our first live record.  However,	 * we want to return DB_REP_STARTUPDONE on the first record we can --	 * but other return values trump this one.  We know we've processed at	 * least one record when rectype is non-zero.	 */	if (ret == 0 && !F_ISSET(rp, DB_LOG_RESEND) &&	    rectype != 0 && rep->stat.st_startup_complete == 0) {		rep->stat.st_startup_complete = 1;		ret = DB_REP_STARTUPDONE;	}	if (ret == 0 && rp->rectype == REP_NEWFILE && lp->db_log_autoremove)		__log_autoremove(dbenv);	if (control_dbt.data != NULL)		__os_ufree(dbenv, control_dbt.data);	if (rec_dbt.data != NULL)		__os_ufree(dbenv, rec_dbt.data);	if (ret == DB_REP_NOTPERM && !F_ISSET(rep, REP_F_RECOVER_LOG) &&	    !IS_ZERO_LSN(max_lsn) && ret_lsnp != NULL)		*ret_lsnp = max_lsn;#ifdef DIAGNOSTIC	if (ret == DB_REP_ISPERM)		RPRINT(dbenv, rep, (dbenv, &mb, "Returning ISPERM [%lu][%lu]",		    (u_long)max_lsn.file, (u_long)max_lsn.offset));	else if (ret == DB_REP_LOGREADY)		RPRINT(dbenv, rep, (dbenv, &mb,		    "Returning LOGREADY up to [%lu][%lu]",		    (u_long)rep->last_lsn.file,		    (u_long)rep->last_lsn.offset));	else if (ret == DB_REP_NOTPERM)		RPRINT(dbenv, rep, (dbenv, &mb, "Returning NOTPERM [%lu][%lu]",		    (u_long)max_lsn.file, (u_long)max_lsn.offset));	else if (ret == DB_REP_STARTUPDONE)		RPRINT(dbenv, rep, (dbenv, &mb,		    "Returning STARTUPDONE [%lu][%lu]",		    (u_long)rp->lsn.file, (u_long)rp->lsn.offset));	else if (ret != 0)		RPRINT(dbenv, rep, (dbenv, &mb, "Returning %d [%lu][%lu]", ret,		    (u_long)max_lsn.file, (u_long)max_lsn.offset));#endif	return (ret);}/* * __rep_process_txn -- * * This is the routine that actually gets a transaction ready for * processing. * * PUBLIC: int __rep_process_txn __P((DB_ENV *, DBT *)); */int__rep_process_txn(dbenv, rec)	DB_ENV *dbenv;	DBT *rec;{	DBT data_dbt, *lock_dbt;	DB_LOCKREQ req, *lvp;	DB_LOGC *logc;	DB_LSN prev_lsn, *lsnp;	DB_REP *db_rep;	LSN_COLLECTION lc;	REP *rep;	__txn_regop_args *txn_args;	__txn_xa_regop_args *prep_args;	u_int32_t lockid, rectype;	u_int i;	int ret, t_ret;	void *txninfo;	db_rep = dbenv->rep_handle;	rep = db_rep->region;	logc = NULL;	txn_args = NULL;	prep_args = NULL;	txninfo = NULL;	memset(&data_dbt, 0, sizeof(data_dbt));	if (F_ISSET(dbenv, DB_ENV_THREAD))		F_SET(&data_dbt, DB_DBT_REALLOC);	/*	 * There are two phases:  First, we have to traverse backwards through	 * the log records gathering the list of all LSNs in the transaction.	 * Once we have this information, we can loop through and then apply it.	 *	 * We may be passed a prepare (if we're restoring a prepare on upgrade)	 * instead of a commit (the common case).  Check which it is and behave	 * appropriately.	 */	memcpy(&rectype, rec->data, sizeof(rectype));	memset(&lc, 0, sizeof(lc));	if (rectype == DB___txn_regop) {		/*		 * We're the end of a transaction.  Make sure this is		 * really a commit and not an abort!		 */		if ((ret = __txn_regop_read(dbenv, rec->data, &txn_args)) != 0)			return (ret);		if (txn_args->opcode != TXN_COMMIT) {			__os_free(dbenv, txn_args);			return (0);		}		prev_lsn = txn_args->prev_lsn;		lock_dbt = &txn_args->locks;	} else {		/* We're a prepare. */		DB_ASSERT(rectype == DB___txn_xa_regop);		if ((ret =		    __txn_xa_regop_read(dbenv, rec->data, &prep_args)) != 0)			return (ret);		prev_lsn = prep_args->prev_lsn;		lock_dbt = &prep_args->locks;	}	/* Get locks. */	if ((ret = __lock_id(dbenv, &lockid)) != 0)		goto err1;	if ((ret =	      __lock_get_list(dbenv, lockid, 0, DB_LOCK_WRITE, lock_dbt)) != 0)		goto err;	/* Phase 1.  Get a list of the LSNs in this transaction, and sort it. */	if ((ret = __rep_collect_txn(dbenv, &prev_lsn, &lc)) != 0)		goto err;	qsort(lc.array, lc.nlsns, sizeof(DB_LSN), __rep_lsn_cmp);	/*	 * The set of records for a transaction may include dbreg_register	 * records.  Create a txnlist so that they can keep track of file	 * state between records.	 */	if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txninfo)) != 0)		goto err;	/* Phase 2: Apply updates. */	if ((ret = __log_cursor(dbenv, &logc)) != 0)		goto err;	for (lsnp = &lc.array[0], i = 0; i < lc.nlsns; i++, lsnp++) {		if ((ret = __log_c_get(logc, lsnp, &data_dbt, DB_SET)) != 0) {			__db_err(dbenv, "failed to read the log at [%lu][%lu]",			    (u_long)lsnp->file, (u_long)lsnp->offset);			goto err;		}		if ((ret = __db_dispatch(dbenv, dbenv->recover_dtab,		    dbenv->recover_dtab_size, &data_dbt, lsnp,		    DB_TXN_APPLY, txninfo)) != 0) {			__db_err(dbenv, "transaction failed at [%lu][%lu]",			    (u_long)lsnp->file, (u_long)lsnp->offset);			goto err;		}	}err:	memset(&req, 0, sizeof(req));	req.op = DB_LOCK_PUT_ALL;	if ((t_ret =	     __lock_vec(dbenv, lockid, 0, &req, 1, &lvp)) != 0 && ret == 0)		ret = t_ret;	if ((t_ret = __lock_id_free(dbenv, lockid)) != 0 && ret == 0)		ret = t_ret;err1:	if (txn_args != NULL)		__os_free(dbenv, txn_args);	if (prep_args != NULL)		__os_free(dbenv, prep_args);	if (lc.array != NULL)		__os_free(dbenv, lc.array);	if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0)		ret = t_ret;	if (txninfo != NULL)		__db_txnlist_end(dbenv, txninfo);	if (F_ISSET(&data_dbt, DB_DBT_REALLOC) && data_dbt.data != NULL)		__os_ufree(dbenv, data_dbt.data);	if (ret == 0)		/*		 * We don't hold the rep mutex, and could miscount if we race.		 */		rep->stat.st_txns_applied++;	return (ret);}/* * __rep_collect_txn *	Recursive function that will let us visit every entry in a transaction *	chain including all child transactions so that we can then apply *	the entire transaction family at once. */static int__rep_collect_txn(dbenv, lsnp, lc)	DB_ENV *dbenv;	DB_LSN *lsnp;	LSN_COLLECTION *lc;{	__txn_child_args *argp;	DB_LOGC *logc;	DB_LSN c_lsn;	DBT data;	u_int32_t rectype;	u_int nalloc;	int ret, t_ret;	memset(&data, 0, sizeof(data));	F_SET(&data, DB_DBT_REALLOC);	if ((ret = __log_cursor(dbenv, &logc)) != 0)		return (ret);	while (!IS_ZERO_LSN(*lsnp) &&	    (ret = __log_c_get(logc, lsnp, &data, DB_SET)) == 0) {		memcpy(&rectype, data.data, sizeof(rectype));		if (rectype == DB___txn_child) {			if ((ret = __txn_child_read(dbenv,			    data.data, &argp)) != 0)				goto err;			c_lsn = argp->c_lsn;			*lsnp = argp->prev_lsn;			__os_free(dbenv, argp);			ret = __rep_collect_txn(dbenv, &c_lsn, lc);		} else {			if (lc->nalloc < lc->nlsns + 1) {				nalloc = lc->nalloc == 0 ? 20 : lc->nalloc * 2;				if ((ret = __os_realloc(dbenv,				    nalloc * sizeof(DB_LSN), &lc->array)) != 0)					goto err;				lc->nalloc = nalloc;			}			lc->array[lc->nlsns++] = *lsnp;			/*			 * Explicitly copy the previous lsn.  The record			 * starts with a u_int32_t record type, a u_int32_t			 * txn id, and then the DB_LSN (prev_lsn) that we			 * want.  We copy explicitly because we have no idea			 * what kind of record this is.			 */			memcpy(lsnp, (u_int8_t *)data.data +			    sizeof(u_int32_t) + sizeof(u_int32_t),			    sizeof(DB_LSN));		}		if (ret != 0)			goto err;	}	if (ret != 0)		__db_err(dbenv, "collect failed at: [%lu][%lu]",		    (u_long)lsnp->file, (u_long)lsnp->offset);err:	if ((t_ret = __log_c_close(logc)) != 0 && ret == 0)		ret = t_ret;	if (data.data != NULL)		__os_ufree(dbenv, data.data);	return (ret);}/* * __rep_lsn_cmp -- *	qsort-type-compatible wrapper for log_compare. */static int__rep_lsn_cmp(lsn1, lsn2)	const void *lsn1, *lsn2;{	return (log_compare((DB_LSN *)lsn1, (DB_LSN *)lsn2));}/* * __rep_newfile -- *	NEWFILE messages have the LSN of the last record in the previous * log file.  When applying a NEWFILE message, make sure we haven't already * swapped files. */static int__rep_newfile(dbenv, rc, lsnp)	DB_ENV *dbenv;	REP_CONTROL *rc;	DB_LSN *lsnp;{	DB_LOG *dblp;	LOG *lp;	dblp = dbenv->lg_handle;	lp = dblp->reginfo.primary;	if (rc->lsn.file + 1 > lp->lsn.file)		return (__log_newfile(dblp, lsnp, 0));	else {		/* We've already applied this NEWFILE.  Just ignore it. */		*lsnp = lp->lsn;		return (0);	}}/* * __rep_tally -- * PUBLIC: int __rep_tally __P((DB_ENV *, REP *, int, int *, * PUBLIC:    u_int32_t, roff_t)); * * Handle incoming vote1 message on a client.  Called with the db_rep * mutex held.  This function will return 0 if we successfully tally * the vote and non-zero if the vote is ignored.  This will record * both VOTE1 and VOTE2 records, depending on which region offset the * caller passed in. */int__rep_tally(dbenv, rep, eid, countp, egen, vtoff)	DB_ENV *dbenv;	REP *rep;	int eid, *countp;	u_int32_t egen;	roff_t vtoff;{	REP_VTALLY *tally, *vtp;	int i;#ifdef DIAGNOSTIC	DB_MSGBUF mb;#else	COMPQUIET(rep, NULL);#endif	tally = R_ADDR((REGINFO *)dbenv->reginfo, vtoff);	i = 0;	vtp = &tally[i];	while (i < *countp) {		/*		 * Ignore votes from earlier elections (i.e. we've heard		 * from this site in this election, but its vote from an		 * earlier election got delayed and we received it now).		 * However, if we happened to hear from an earlier vote		 * and we recorded it and we're now hearing from a later		 * election we want to keep the updated one.  Note that		 * updating the entry will not increase the count.		 * Also ignore votes that are duplicates.		 */		if (vtp->eid == eid) {			RPRINT(dbenv, rep, (dbenv, &mb,			    "Tally found[%d] (%d, %lu), this vote (%d, %lu)",				    i, vtp->eid, (u_long)vtp->egen,				    eid, (u_long)egen));			if (vtp->egen >= egen)				return (1);			else {				vtp->egen = egen;				return (0);			}		}		i++;		vtp = &tally[i];	}	/*	 * If we get here, we have a new voter we haven't	 * seen before.  Tally this vote.	 */#ifdef DIAGNOSTIC	if (vtoff == rep->tally_off)		RPRINT(dbenv, rep, (dbenv, &mb, "Tallying VOTE1[%d] (%d, %lu)",		    i, eid, (u_long)egen));	else		RPRINT(dbenv, rep, (dbenv, &mb, "Tallying VOTE2[%d] (%d, %lu)",		    i, eid, (u_long)egen));#endif	vtp->eid = eid;	vtp->egen = egen;	(*countp)++;	return (0);}/* * __rep_cmp_vote -- * PUBLIC: void __rep_cmp_vote __P((DB_ENV *, REP *, int *, DB_LSN *, * PUBLIC:     int, u_int32_t, u_int32_t)); * * Compare incoming vote1 message on a client.  Called with the db_rep * mutex held. */void__rep_cmp_vote(dbenv, rep, eidp, lsnp, priority, gen, tiebreaker)	DB_ENV *dbenv;	REP *rep;	int *eidp;	DB_LSN *lsnp;	int priority;	u_int32_t gen, tiebreaker;{	int cmp;#ifdef DIAGNOSTIC	DB_MSGBUF mb;#else	COMPQUIET(dbenv, NULL);#endif	cmp = log_compare(lsnp, &rep->w_lsn);	/*	 * If we've seen more than one, compare us to the best so far.	 * If we're the first, make ourselves the winner to start.	 */	if (rep->sites > 1 && priority != 0) {		/*		 * LSN is primary determinant. Then priority if LSNs		 * are equal, then tiebreaker if both are equal.		 */		if (cmp > 0 ||		    (cmp == 0 && (priority > rep->w_priority ||		    (priority == rep->w_priority &&		    (tiebreaker > rep->w_tiebreaker))))) {			RPRINT(dbenv, rep, (dbenv, &mb, "Accepting new vote"));			rep->winner = *eidp;			rep->w_priority = priority;			rep->w_lsn = *lsnp;			rep->w_gen = gen;			rep->w_tiebreaker = tiebreaker;		}	} else if (rep->sites == 1) {		if (priority != 0) {			/* Make ourselves the winner to start. */			rep->winner = *eidp;			rep->w_priority = priority;			rep->w_gen = gen;			rep->w_lsn = *lsnp;			rep->w_tiebreaker = tiebreaker;		} else {			rep->winner = DB_EID_INVALID;			rep->w_priority = 0;			rep->w_gen = 0;			ZERO_LSN(rep->w_lsn);			rep->w_tiebreaker = 0;		}	}	return;}/* * __rep_cmp_vote2 -- * PUBLIC: int __rep_cmp_vote2 __P((DB_ENV *, REP *, int, u_int32_t)); * * Compare incoming vote2 message with vote1's we've recorded.  Called * with the db_rep mutex held.  We return 0 if the VOTE2 is from a * site we've heard from and it is from this election.  Otherwise we return 1. */int__rep_cmp_vote2(dbenv, rep, eid, egen)	DB_ENV *dbenv;	REP *rep;

⌨️ 快捷键说明

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