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

📄 rep_method.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (nsites <= 0) {		__db_err(dbenv,		    "DB_ENV->rep_elect: nsites must be greater than 0");		return (EINVAL);	}	if (nvotes < 0) {		__db_err(dbenv,		    "DB_ENV->rep_elect: nvotes may not be negative");		return (EINVAL);	}	if (priority < 0) {		__db_err(dbenv,		    "DB_ENV->rep_elect: priority may not be negative");		return (EINVAL);	}	if (nsites < nvotes) {		__db_err(dbenv,    "DB_ENV->rep_elect: nvotes (%d) is larger than nsites (%d)",		    nvotes, nsites);		return (EINVAL);	}	ack = nvotes;	/* If they give us a 0 for nvotes, default to simple majority.  */	if (nvotes == 0)		ack = (nsites / 2) + 1;	/*	 * XXX	 * If users give us less than a majority, they run the risk of	 * having a network partition.  However, this also allows the	 * scenario of master/1 client to elect the client.  Allow	 * sub-majority values, but give a warning.	 */	if (nvotes <= (nsites / 2)) {		__db_err(dbenv,    "DB_ENV->rep_elect:WARNING: nvotes (%d) is sub-majority with nsites (%d)",		    nvotes, nsites);	}	db_rep = dbenv->rep_handle;	rep = db_rep->region;	dblp = dbenv->lg_handle;	RPRINT(dbenv, rep,	    (dbenv, &mb, "Start election nsites %d, ack %d, priority %d",	    nsites, ack, priority));	R_LOCK(dbenv, &dblp->reginfo);	lsn = ((LOG *)dblp->reginfo.primary)->lsn;	R_UNLOCK(dbenv, &dblp->reginfo);	orig_tally = 0;	to = timeout;	if ((ret = __rep_elect_init(dbenv,	    &lsn, nsites, ack, priority, &in_progress, &orig_tally)) != 0) {		if (ret == DB_REP_NEWMASTER) {			ret = 0;			*eidp = dbenv->rep_eid;		}		goto err;	}	/*	 * If another thread is in the middle of an election we	 * just quietly return and not interfere.	 */	if (in_progress) {		*eidp = rep->master_id;		return (0);	}	(void)__rep_send_message(dbenv,	    DB_EID_BROADCAST, REP_MASTER_REQ, NULL, NULL, 0);	ret = __rep_wait(dbenv, to/4, eidp, REP_F_EPHASE1);	switch (ret) {		case 0:			/* Check if we found a master. */			if (*eidp != DB_EID_INVALID) {				RPRINT(dbenv, rep, (dbenv, &mb,				    "Found master %d", *eidp));				goto edone;			}			/*			 * If we didn't find a master, continue			 * the election.			 */			break;		case DB_REP_EGENCHG:			/*			 * Egen changed, just continue with election.			 */			break;		case DB_TIMEOUT:			RPRINT(dbenv, rep, (dbenv, &mb,			    "Did not find master.  Sending vote1"));			break;		default:			goto err;	}restart:	/* Generate a randomized tiebreaker value. */	__os_unique_id(dbenv, &tiebreaker);	MUTEX_LOCK(dbenv, db_rep->rep_mutexp);	F_SET(rep, REP_F_EPHASE1 | REP_F_NOARCHIVE);	F_CLR(rep, REP_F_TALLY);	/*	 * We are about to participate at this egen.  We must	 * write out the next egen before participating in this one	 * so that if we crash we can never participate in this egen	 * again.	 */	if ((ret = __rep_write_egen(dbenv, rep->egen + 1)) != 0)		goto lockdone;	/* Tally our own vote */	if (__rep_tally(dbenv, rep, rep->eid, &rep->sites, rep->egen,	    rep->tally_off) != 0) {		ret = EINVAL;		goto lockdone;	}	__rep_cmp_vote(dbenv, rep, &rep->eid, &lsn, priority, rep->gen,	    tiebreaker);	RPRINT(dbenv, rep, (dbenv, &mb, "Beginning an election"));	/* Now send vote */	send_vote = DB_EID_INVALID;	egen = rep->egen;	MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);	__rep_send_vote(dbenv, &lsn, nsites, ack, priority, tiebreaker, egen,	    DB_EID_BROADCAST, REP_VOTE1);	DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTVOTE1, ret, NULL);	ret = __rep_wait(dbenv, to, eidp, REP_F_EPHASE1);	switch (ret) {		case 0:			/* Check if election complete or phase complete. */			if (*eidp != DB_EID_INVALID) {				RPRINT(dbenv, rep, (dbenv, &mb,				    "Ended election phase 1 %d", ret));				goto edone;			}			goto phase2;		case DB_REP_EGENCHG:			if (to > timeout)				to = timeout;			to = (to * 8) / 10;			RPRINT(dbenv, rep, (dbenv, &mb,"Egen changed while waiting. Now %lu.  New timeout %lu, orig timeout %lu",			    (u_long)rep->egen, (u_long)to, (u_long)timeout));			/*			 * If the egen changed while we were sleeping, that			 * means we're probably late to the next election,			 * so we'll backoff our timeout so that we don't get			 * into an out-of-phase election scenario.			 *			 * Backoff to 80% of the current timeout.			 */			goto restart;		case DB_TIMEOUT:			break;		default:			goto err;	}	/*	 * If we got here, we haven't heard from everyone, but we've	 * run out of time, so it's time to decide if we have enough	 * votes to pick a winner and if so, to send out a vote to	 * the winner.	 */	MUTEX_LOCK(dbenv, db_rep->rep_mutexp);	/*	 * If our egen changed while we were waiting.  We need to	 * essentially reinitialize our election.	 */	if (egen != rep->egen) {		MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);		RPRINT(dbenv, rep, (dbenv, &mb, "Egen changed from %lu to %lu",		    (u_long)egen, (u_long)rep->egen));		goto restart;	}	if (rep->sites >= rep->nvotes) {		/* We think we've seen enough to cast a vote. */		send_vote = rep->winner;		/*		 * See if we won.  This will make sure we		 * don't count ourselves twice if we're racing		 * with incoming votes.		 */		if (rep->winner == rep->eid) {			(void)__rep_tally(dbenv, rep, rep->eid, &rep->votes,			    egen, rep->v2tally_off);			RPRINT(dbenv, rep, (dbenv, &mb,			    "Counted my vote %d", rep->votes));		}		F_SET(rep, REP_F_EPHASE2);		F_CLR(rep, REP_F_EPHASE1);	}	MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);	if (send_vote == DB_EID_INVALID) {		/* We do not have enough votes to elect. */		RPRINT(dbenv, rep, (dbenv, &mb,		    "Not enough votes to elect: recvd %d of %d from %d sites",		    rep->sites, rep->nvotes, rep->nsites));		ret = DB_REP_UNAVAIL;		goto err;	} else {		/*		 * We have seen enough vote1's.  Now we need to wait		 * for all the vote2's.		 */		if (send_vote != rep->eid) {			RPRINT(dbenv, rep, (dbenv, &mb, "Sending vote"));			__rep_send_vote(dbenv, NULL, 0, 0, 0, 0, egen,			    send_vote, REP_VOTE2);			/*			 * If we are NOT the new master we want to send			 * our vote to the winner, and wait longer.  The			 * reason is that the winner may be "behind" us			 * in the election waiting and if the master is			 * down, the winner will wait the full timeout			 * and we want to give the winner enough time to			 * process all the votes.  Otherwise we could			 * incorrectly return DB_REP_UNAVAIL and start a			 * new election before the winner can declare			 * itself.			 */			to = to * 2;		}phase2:		ret = __rep_wait(dbenv, to, eidp, REP_F_EPHASE2);		RPRINT(dbenv, rep, (dbenv, &mb,		    "Ended election phase 2 %d", ret));		switch (ret) {			case 0:				goto edone;			case DB_REP_EGENCHG:				if (to > timeout)					to = timeout;				to = (to * 8) / 10;				RPRINT(dbenv, rep, (dbenv, &mb,"While waiting egen changed to %lu.  Phase 2 New timeout %lu, orig timeout %lu",				    (u_long)rep->egen,				    (u_long)to, (u_long)timeout));				goto restart;			case DB_TIMEOUT:				ret = DB_REP_UNAVAIL;				break;			default:				goto err;		}		MUTEX_LOCK(dbenv, db_rep->rep_mutexp);		if (egen != rep->egen) {			MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			RPRINT(dbenv, rep, (dbenv, &mb,			    "Egen ph2 changed from %lu to %lu",			    (u_long)egen, (u_long)rep->egen));			goto restart;		}		done = rep->votes >= rep->nvotes;		RPRINT(dbenv, rep, (dbenv, &mb,		    "After phase 2: done %d, votes %d, nsites %d",		    done, rep->votes, rep->nsites));		if (send_vote == rep->eid && done) {			__rep_elect_master(dbenv, rep, eidp);			ret = 0;			goto lockdone;		}		MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);	}err:	MUTEX_LOCK(dbenv, db_rep->rep_mutexp);lockdone:	/*	 * If we get here because of a non-election error, then we	 * did not tally our vote.  The only non-election error is	 * from elect_init where we were unable to grow_sites.  In	 * that case we do not want to discard all known election info.	 */	if (ret == 0 || ret == DB_REP_UNAVAIL)		__rep_elect_done(dbenv, rep);	else if (orig_tally)		F_SET(rep, orig_tally);	/*	 * If the election finished elsewhere, we need to decrement	 * the elect_th anyway.	 */	if (0)edone:		MUTEX_LOCK(dbenv, db_rep->rep_mutexp);	rep->elect_th = 0;	RPRINT(dbenv, rep, (dbenv, &mb,	    "Ended election with %d, sites %d, egen %lu, flags 0x%lx",	    ret, rep->sites, (u_long)rep->egen, (u_long)rep->flags));	MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);DB_TEST_RECOVERY_LABEL	return (ret);}/* * __rep_elect_init *	Initialize an election.  Sets beginp non-zero if the election is * already in progress; makes it 0 otherwise. */static int__rep_elect_init(dbenv, lsnp, nsites, nvotes, priority, beginp, otally)	DB_ENV *dbenv;	DB_LSN *lsnp;	int nsites, nvotes, priority;	int *beginp;	u_int32_t *otally;{	DB_REP *db_rep;	REP *rep;	int ret;	db_rep = dbenv->rep_handle;	rep = db_rep->region;	ret = 0;	/* We may miscount, as we don't hold the replication mutex here. */	rep->stat.st_elections++;	/* If we are already a master; simply broadcast that fact and return. */	if (F_ISSET(rep, REP_F_MASTER)) {		(void)__rep_send_message(dbenv,		    DB_EID_BROADCAST, REP_NEWMASTER, lsnp, NULL, 0);		rep->stat.st_elections_won++;		return (DB_REP_NEWMASTER);	}	MUTEX_LOCK(dbenv, db_rep->rep_mutexp);	if (otally != NULL)		*otally = F_ISSET(rep, REP_F_TALLY);	*beginp = IN_ELECTION(rep) || rep->elect_th;	if (!*beginp) {		/*		 * Make sure that we always initialize all the election fields		 * before putting ourselves in an election state.  That means		 * issuing calls that can fail (allocation) before setting all		 * the variables.		 */		if (nsites > rep->asites &&		    (ret = __rep_grow_sites(dbenv, nsites)) != 0)			goto err;		DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTINIT, ret, NULL);		rep->elect_th = 1;		rep->nsites = nsites;		rep->nvotes = nvotes;		rep->priority = priority;		rep->master_id = DB_EID_INVALID;	}DB_TEST_RECOVERY_LABELerr:	MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);	return (ret);}/* * __rep_elect_master *	Set up for new master from election.  Must be called with *	the db_rep->rep_mutex held. * * PUBLIC: void __rep_elect_master __P((DB_ENV *, REP *, int *)); */void__rep_elect_master(dbenv, rep, eidp)	DB_ENV *dbenv;	REP *rep;	int *eidp;{#ifdef DIAGNOSTIC	DB_MSGBUF mb;#else	COMPQUIET(dbenv, NULL);#endif	rep->master_id = rep->eid;	F_SET(rep, REP_F_MASTERELECT);	if (eidp != NULL)		*eidp = rep->master_id;	rep->stat.st_elections_won++;	RPRINT(dbenv, rep, (dbenv, &mb,	    "Got enough votes to win; election done; winner is %d, gen %lu",	    rep->master_id, (u_long)rep->gen));}static int__rep_wait(dbenv, timeout, eidp, flags)	DB_ENV *dbenv;	u_int32_t timeout;	int *eidp;	u_int32_t flags;{	DB_REP *db_rep;	REP *rep;	int done, echg;	u_int32_t egen, sleeptime;	done = echg = 0;	db_rep = dbenv->rep_handle;	rep = db_rep->region;	egen = rep->egen;	/*	 * The user specifies an overall timeout function, but checking	 * is cheap and the timeout may be a generous upper bound.	 * Sleep repeatedly for the smaller of .5s and timeout/10.	 */	sleeptime = (timeout > 5000000) ? 500000 : timeout / 10;	if (sleeptime == 0)		sleeptime++;	while (timeout > 0) {		__os_sleep(dbenv, 0, sleeptime);		MUTEX_LOCK(dbenv, db_rep->rep_mutexp);		echg = egen != rep->egen;		done = !F_ISSET(rep, flags) && rep->master_id != DB_EID_INVALID;		*eidp = rep->master_id;		MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);		if (done)			return (0);		if (echg)			return (DB_REP_EGENCHG);		if (timeout > sleeptime)			timeout -= sleeptime;		else			timeout = 0;	}	return (DB_TIMEOUT);}/* * __rep_flush -- *	Re-push the last log record to all clients, in case they've lost * messages and don't know it. */static int__rep_flush(dbenv)	DB_ENV *dbenv;{	DBT rec;	DB_LOGC *logc;	DB_LSN lsn;	int ret, t_ret;	PANIC_CHECK(dbenv);	ENV_REQUIRES_CONFIG(dbenv, dbenv->rep_handle, "rep_flush", DB_INIT_REP);	if ((ret = __log_cursor(dbenv, &logc)) != 0)		return (ret);	memset(&rec, 0, sizeof(rec));	memset(&lsn, 0, sizeof(lsn));	if ((ret = __log_c_get(logc, &lsn, &rec, DB_LAST)) != 0)		goto err;	(void)__rep_send_message(dbenv,	    DB_EID_BROADCAST, REP_LOG, &lsn, &rec, 0);err:	if ((t_ret = __log_c_close(logc)) != 0 && ret == 0)		ret = t_ret;	return (ret);}

⌨️ 快捷键说明

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