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

📄 rep_record.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
		ret = __rep_send_file(dbenv, rec, *eidp);		goto errlock;#endif	case REP_FILE_FAIL:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		/*		 * XXX		 */		break;	case REP_LOG:	case REP_LOG_MORE:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		is_dup = 0;		ret = __rep_apply(dbenv, rp, rec, ret_lsnp, &is_dup);		switch (ret) {		/*		 * We're in an internal backup and we've gotten 		 * all the log we need to run recovery.  Do so now.		 */		case DB_REP_LOGREADY:			if ((ret = __log_flush(dbenv, NULL)) != 0)				goto errlock;			if ((ret = __rep_verify_match(dbenv, &rep->last_lsn,			    savetime)) == 0) {				MUTEX_LOCK(dbenv, db_rep->rep_mutexp);				ZERO_LSN(rep->first_lsn);				ZERO_LSN(rep->last_lsn);				F_CLR(rep, REP_F_RECOVER_LOG);				MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			}			break;		/*		 * If we get any of the "normal" returns, we only process		 * LOG_MORE if this is not a duplicate record.  If the 		 * record is a duplicate we don't want to handle LOG_MORE		 * and request a multiple data stream (or trigger internal		 * initialization) since this could be a very old record		 * that no longer exists on the master.		 */		case DB_REP_ISPERM:		case DB_REP_NOTPERM:		case 0:			if (is_dup)				goto errlock;			else				break;		/*		 * Any other return (errors), we're done.		 */		default:			goto errlock;		}		if (rp->rectype == REP_LOG_MORE) {			MUTEX_LOCK(dbenv, db_rep->rep_mutexp);			master = rep->master_id;			MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			R_LOCK(dbenv, &dblp->reginfo);			lsn = lp->lsn;			R_UNLOCK(dbenv, &dblp->reginfo);			/*			 * If the master_id is invalid, this means that since			 * the last record was sent, somebody declared an			 * election and we may not have a master to request			 * things of.			 *			 * This is not an error;  when we find a new master,			 * we'll re-negotiate where the end of the log is and			 * try to bring ourselves up to date again anyway.			 */			MUTEX_LOCK(dbenv, db_rep->db_mutexp);			if (master == DB_EID_INVALID)				ret = 0;			/*			 * If we've asked for a bunch of records, it could			 * either be from a LOG_REQ or ALL_REQ.  If we're			 * waiting for a gap to be filled, call loggap_req,			 * otherwise use ALL_REQ again.			 */			else if (IS_ZERO_LSN(lp->waiting_lsn)) {				MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);				if (__rep_send_message(dbenv,				    master, REP_ALL_REQ, &lsn, NULL, 0) != 0)					break;			} else {				__rep_loggap_req(dbenv, rep, &lsn, 1);				MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);			}		}		goto errlock;	case REP_LOG_REQ:		MASTER_ONLY(rep, rp);		if (rec != NULL && rec->size != 0) {			RPRINT(dbenv, rep, (dbenv, &mb,			    "[%lu][%lu]: LOG_REQ max lsn: [%lu][%lu]",			    (u_long) rp->lsn.file, (u_long)rp->lsn.offset,			    (u_long)((DB_LSN *)rec->data)->file,			    (u_long)((DB_LSN *)rec->data)->offset));		}		/*		 * There are three different cases here.		 * 1. We asked for a particular LSN and got it.		 * 2. We asked for an LSN and it's not found because it is		 *	beyond the end of a log file and we need a NEWFILE msg.		 *	and then the record that was requested.		 * 3. We asked for an LSN and it simply doesn't exist, but		 *    doesn't meet any of those other criteria, in which case		 *    it's an error (that should never happen).		 * If we have a valid LSN and the request has a data_dbt with		 * it, then we need to send all records up to the LSN in the		 * data dbt.		 */		oldfilelsn = lsn = rp->lsn;		if ((ret = __log_cursor(dbenv, &logc)) != 0)			goto errlock;		memset(&data_dbt, 0, sizeof(data_dbt));		ret = __log_c_get(logc, &lsn, &data_dbt, DB_SET);		if (ret == 0) /* Case 1 */			(void)__rep_send_message(dbenv,			   *eidp, REP_LOG, &lsn, &data_dbt, DB_LOG_RESEND);		else if (ret == DB_NOTFOUND) {			R_LOCK(dbenv, &dblp->reginfo);			endlsn = lp->lsn;			R_UNLOCK(dbenv, &dblp->reginfo);			if (endlsn.file > lsn.file) {				/*				 * Case 2:				 * Need to find the LSN of the last record in				 * file lsn.file so that we can send it with				 * the NEWFILE call.  In order to do that, we				 * need to try to get {lsn.file + 1, 0} and				 * then backup.				 */				endlsn.file = lsn.file + 1;				endlsn.offset = 0;				if ((ret = __log_c_get(logc,				    &endlsn, &data_dbt, DB_SET)) != 0 ||				    (ret = __log_c_get(logc,					&endlsn, &data_dbt, DB_PREV)) != 0) {					RPRINT(dbenv, rep, (dbenv, &mb,					    "Unable to get prev of [%lu][%lu]",					    (u_long)lsn.file,					    (u_long)lsn.offset));					/*					 * We want to push the error back					 * to the client so that the client					 * does an internal backup.  The					 * client asked for a log record					 * we no longer have and it is					 * outdated.					 * XXX - This could be optimized by					 * having the master perform and					 * send a REP_UPDATE message.  We					 * currently want the client to set					 * up its 'update' state prior to					 * requesting REP_UPDATE_REQ.					 */					ret = 0;					(void)__rep_send_message(dbenv, *eidp,					    REP_VERIFY_FAIL, &rp->lsn, NULL, 0);				} else {					endlsn.offset += logc->c_len;					(void)__rep_send_message(dbenv, *eidp,					    REP_NEWFILE, &endlsn, NULL, 0);				}			} else {				/* Case 3 */				__db_err(dbenv,				    "Request for LSN [%lu][%lu] fails",				    (u_long)lsn.file, (u_long)lsn.offset);				DB_ASSERT(0);				ret = EINVAL;			}		}		/*		 * If the user requested a gap, send the whole thing,		 * while observing the limits from set_rep_limit.		 */		MUTEX_LOCK(dbenv, db_rep->rep_mutexp);		gbytes = rep->gbytes;		bytes = rep->bytes;		MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);		check_limit = gbytes != 0 || bytes != 0;		type = REP_LOG;		while (ret == 0 && rec != NULL && rec->size != 0 &&		    type == REP_LOG) {			if ((ret =			    __log_c_get(logc, &lsn, &data_dbt, DB_NEXT)) != 0) {				if (ret == DB_NOTFOUND)					ret = 0;				break;			}			if (log_compare(&lsn, (DB_LSN *)rec->data) >= 0)				break;			/*			 * When a log file changes, we'll have a real log			 * record with some lsn [n][m], and we'll also want			 * to send a NEWFILE message with lsn [n-1][MAX].			 */			if (lsn.file != oldfilelsn.file)				(void)__rep_send_message(dbenv,				    *eidp, REP_NEWFILE, &oldfilelsn, NULL, 0);			if (check_limit) {				/*				 * data_dbt.size is only the size of the log				 * record;  it doesn't count the size of the				 * control structure. Factor that in as well				 * so we're not off by a lot if our log records				 * are small.				 */				while (bytes <				    data_dbt.size + sizeof(REP_CONTROL)) {					if (gbytes > 0) {						bytes += GIGABYTE;						--gbytes;						continue;					}					/*					 * We don't hold the rep mutex,					 * and may miscount.					 */					rep->stat.st_nthrottles++;					type = REP_LOG_MORE;					goto send1;				}				bytes -= (data_dbt.size + sizeof(REP_CONTROL));			}send1:			 if (__rep_send_message(dbenv, *eidp, type,			    &lsn, &data_dbt, DB_LOG_RESEND) != 0)				break;			/*			 * If we are about to change files, then we'll need the			 * last LSN in the previous file.  Save it here.			 */			oldfilelsn = lsn;			oldfilelsn.offset += logc->c_len;		}		if ((t_ret = __log_c_close(logc)) != 0 && ret == 0)			ret = t_ret;		goto errlock;	case REP_NEWSITE:		/* We don't hold the rep mutex, and may miscount. */		rep->stat.st_newsites++;		/* This is a rebroadcast; simply tell the application. */		if (F_ISSET(rep, REP_F_MASTER)) {			dblp = dbenv->lg_handle;			lp = dblp->reginfo.primary;			R_LOCK(dbenv, &dblp->reginfo);			lsn = lp->lsn;			R_UNLOCK(dbenv, &dblp->reginfo);			(void)__rep_send_message(dbenv,			    *eidp, REP_NEWMASTER, &lsn, NULL, 0);		}		ret = DB_REP_NEWSITE;		goto errlock;	case REP_NEWCLIENT:		/*		 * This message was received and should have resulted in the		 * application entering the machine ID in its machine table.		 * We respond to this with an ALIVE to send relevant information		 * to the new client (if we are a master, we'll send a		 * NEWMASTER, so we only need to send the ALIVE if we're a		 * client).  But first, broadcast the new client's record to		 * all the clients.		 */		(void)__rep_send_message(dbenv,		    DB_EID_BROADCAST, REP_NEWSITE, &rp->lsn, rec, 0);		ret = DB_REP_NEWSITE;		if (F_ISSET(rep, REP_F_CLIENT)) {			MUTEX_LOCK(dbenv, db_rep->rep_mutexp);			egen = rep->egen;			if (*eidp == rep->master_id)				rep->master_id = DB_EID_INVALID;			MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			data_dbt.data = &egen;			data_dbt.size = sizeof(egen);			(void)__rep_send_message(dbenv, DB_EID_BROADCAST,			    REP_ALIVE, &rp->lsn, &data_dbt, 0);			goto errlock;		}		/* FALLTHROUGH */	case REP_MASTER_REQ:		if (F_ISSET(rep, REP_F_MASTER)) {			R_LOCK(dbenv, &dblp->reginfo);			lsn = lp->lsn;			R_UNLOCK(dbenv, &dblp->reginfo);			(void)__rep_send_message(dbenv,			    DB_EID_BROADCAST, REP_NEWMASTER, &lsn, NULL, 0);		}		/*		 * If there is no master, then we could get into a state		 * where an old client lost the initial ALIVE message and		 * is calling an election under an old gen and can		 * never get to the current gen.		 */		if (F_ISSET(rep, REP_F_CLIENT) && rp->gen < gen) {			MUTEX_LOCK(dbenv, db_rep->rep_mutexp);			egen = rep->egen;			if (*eidp == rep->master_id)				rep->master_id = DB_EID_INVALID;			MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			data_dbt.data = &egen;			data_dbt.size = sizeof(egen);			(void)__rep_send_message(dbenv, *eidp,			    REP_ALIVE, &rp->lsn, &data_dbt, 0);			goto errlock;		}		goto errlock;	case REP_NEWFILE:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		ret = __rep_apply(dbenv, rp, rec, ret_lsnp, NULL);		goto errlock;	case REP_NEWMASTER:		ANYSITE(rep);		if (F_ISSET(rep, REP_F_MASTER) &&		    *eidp != dbenv->rep_eid) {			/* We don't hold the rep mutex, and may miscount. */			rep->stat.st_dupmasters++;			ret = DB_REP_DUPMASTER;			(void)__rep_send_message(dbenv,			    DB_EID_BROADCAST, REP_DUPMASTER, NULL, NULL, 0);			goto errlock;		}		ret = __rep_new_master(dbenv, rp, *eidp);		goto errlock;	case REP_PAGE:	case REP_PAGE_MORE:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		ret = __rep_page(dbenv, *eidp, rp, rec);		break;	case REP_PAGE_FAIL:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		ret = __rep_page_fail(dbenv, *eidp, rec);		break;	case REP_PAGE_REQ:		MASTER_ONLY(rep, rp);		MASTER_UPDATE(dbenv, renv);		ret = __rep_page_req(dbenv, *eidp, rec);		break;	case REP_UPDATE:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		ret = __rep_update_setup(dbenv, *eidp, rp, rec);		break;	case REP_UPDATE_REQ:		MASTER_ONLY(rep, rp);		infop = dbenv->reginfo;		renv = infop->primary;		MASTER_UPDATE(dbenv, renv);		ret = __rep_update_req(dbenv, *eidp);		break;	case REP_VERIFY:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		if (IS_ZERO_LSN(lp->verify_lsn))			goto errlock;		if ((ret = __log_cursor(dbenv, &logc)) != 0)			goto errlock;		memset(&mylog, 0, sizeof(mylog));		if ((ret = __log_c_get(logc, &rp->lsn, &mylog, DB_SET)) != 0)			goto rep_verify_err;		match = 0;		memcpy(&rectype, mylog.data, sizeof(rectype));		if (mylog.size == rec->size &&		    memcmp(mylog.data, rec->data, rec->size) == 0)			match = 1;		DB_ASSERT(rectype == DB___txn_ckp);		/*		 * If we don't have a match, backup to the previous		 * checkpoint and try again.		 */		if (match == 0) {			ZERO_LSN(lsn);			if ((ret = __log_backup(dbenv, logc, &rp->lsn, &lsn,			    LASTCKP_CMP)) == 0) {				MUTEX_LOCK(dbenv, db_rep->db_mutexp);				lp->verify_lsn = lsn;				lp->rcvd_recs = 0;				lp->wait_recs = rep->request_gap;				MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);				(void)__rep_send_message(dbenv,				    *eidp, REP_VERIFY_REQ, &lsn, NULL, 0);			} else if (ret == DB_NOTFOUND) {				/*				 * We've either run out of records because				 * logs have been removed or we've rolled back				 * all the way to the beginning.  In the latter				 * we don't think these sites were ever part of				 * the same environment and we'll say so.				 * In the former, request internal backup.				 */				if (rp->lsn.file == 1) {					__db_err(dbenv,			"Client was never part of master's environment");					ret = EINVAL;				} else {					rep->stat.st_outdated++;					R_LOCK(dbenv, &dblp->reginfo);					lsn = lp->lsn;					R_UNLOCK(dbenv, &dblp->reginfo);					MUTEX_LOCK(dbenv, db_rep->rep_mutexp);					F_CLR(rep, REP_F_RECOVER_VERIFY);					F_SET(rep, REP_F_RECOVER_UPDATE);					ZERO_LSN(rep->first_lsn);					MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);					(void)__rep_send_message(dbenv,					    *eidp, REP_UPDATE_REQ, NULL,					    NULL, 0);				}			}		} else			ret = __rep_verify_match(dbenv, &rp->lsn, savetime);rep_verify_err:	if ((t_ret = __log_c_close(logc)) != 0 && ret == 0)			ret = t_ret;		goto errlock;	case REP_VERIFY_FAIL:		CLIENT_ONLY(rep, rp);		MASTER_CHECK(dbenv, *eidp, rep);		/*		 * If any recovery flags are set, but not VERIFY,		 * then we ignore this message.  We are already		 * in the middle of updating.		 */		if (F_ISSET(rep, REP_F_RECOVER_MASK) &&		    !F_ISSET(rep, REP_F_RECOVER_VERIFY))			goto errlock;		rep->stat.st_outdated++;		MUTEX_LOCK(dbenv, db_rep->db_mutexp);		MUTEX_LOCK(dbenv, db_rep->rep_mutexp);		/*		 * We don't want an old or delayed VERIFY_FAIL		 * message to throw us into internal initialization		 * when we shouldn't be.  		 *		 * Only go into internal initialization if:		 * We are in RECOVER_VERIFY and this LSN == verify_lsn.		 * We are not in any RECOVERY and we are expecting		 *    an LSN that no longer exists on the master.		 * Otherwise, ignore this message.		 */		if (((F_ISSET(rep, REP_F_RECOVER_VERIFY)) &&		    log_compare(&rp->lsn, &lp->verify_lsn) == 0) ||		    (F_ISSET(rep, REP_F_RECOVER_MASK) == 0 &&		    log_compare(&rp->lsn, &lp->ready_lsn) >= 0)) {			F_CLR(rep, REP_F_RECOVER_VERIFY);			F_SET(rep, REP_F_RECOVER_UPDATE);			ZERO_LSN(rep->first_lsn);			lp->wait_recs = rep->request_gap;			MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);			MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);			(void)__rep_send_message(dbenv,			    *eidp, REP_UPDATE_REQ, NULL, NULL, 0);

⌨️ 快捷键说明

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