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

📄 env_recover.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
	for (ret = __log_c_get(logc, &lsn, &data, DB_NEXT);	    ret == 0; ret = __log_c_get(logc, &lsn, &data, DB_NEXT)) {		if (dbenv->db_feedback != NULL) {			progress = 67 + (int)(33 * (__lsn_diff(&first_lsn,			    &last_lsn, &lsn, log_size, 1) / nfiles));			dbenv->db_feedback(dbenv, DB_RECOVER, progress);		}		tlsn = lsn;		ret = __db_dispatch(dbenv, dbenv->recover_dtab,		    dbenv->recover_dtab_size, &data, &tlsn,		    DB_TXN_FORWARD_ROLL, txninfo);		if (ret != 0) {			if (ret != DB_TXN_CKP)				goto msgerr;			else				ret = 0;		}		/*		 * If we are recovering to a timestamp or an LSN,		 * we need to make sure that we don't try to roll		 * forward beyond the soon-to-be end of log.		 */		if (log_compare(&lsn, &stop_lsn) >= 0)			break;	}	if (ret == DB_NOTFOUND)		ret = __db_log_corrupt(dbenv, &lsn);	if (ret != 0)		goto err;#ifndef HAVE_FTRUNCATE	/*	 * Process any pages that were on the limbo list and move them to	 * the free list.  Do this before checkpointing the database.	 */	if ((ret = __db_do_the_limbo(dbenv, NULL, NULL, txninfo,	      dbenv->tx_timestamp != 0 ? LIMBO_TIMESTAMP : LIMBO_RECOVER)) != 0)		goto err;#endif	if (max_lsn == NULL)		region->last_txnid = ((DB_TXNHEAD *)txninfo)->maxid;	if (dbenv->tx_timestamp != 0) {		/* We are going to truncate, so we'd best close the cursor. */		if (logc != NULL && (ret = __log_c_close(logc)) != 0)			goto err;		logc = NULL;		/* Flush everything to disk, we are losing the log. */		if ((ret = __memp_sync(dbenv, NULL)) != 0)			goto err;		region->last_ckp = ((DB_TXNHEAD *)txninfo)->ckplsn;		if ((ret = __log_vtruncate(dbenv,		    &((DB_TXNHEAD *)txninfo)->maxlsn,		    &((DB_TXNHEAD *)txninfo)->ckplsn, trunclsn)) != 0)			goto err;#ifndef HAVE_FTRUNCATE		/*		 * Generate logging compensation records.		 * If we crash during/after vtruncate we may have		 * pages missing from the free list since they		 * if we roll things further back from here.		 * These pages are only known in memory at this pont.		 */		 if ((ret = __db_do_the_limbo(dbenv,		       NULL, NULL, txninfo, LIMBO_COMPENSATE)) != 0)			goto err;#endif	}	/* Take a checkpoint here to force any dirty data pages to disk. */	if ((ret = __txn_checkpoint(dbenv, 0, 0, DB_FORCE)) != 0)		goto err;	/* Close all the db files that are open. */	if ((ret = __dbreg_close_files(dbenv)) != 0)		goto err;done:	if (max_lsn != NULL) {		if (!IS_ZERO_LSN(((DB_TXNHEAD *)txninfo)->ckplsn))			region->last_ckp = ((DB_TXNHEAD *)txninfo)->ckplsn;		else if ((ret =		    __txn_findlastckp(dbenv, &region->last_ckp, max_lsn)) != 0)			goto err;		/* We are going to truncate, so we'd best close the cursor. */		if (logc != NULL && (ret = __log_c_close(logc)) != 0)			goto err;		if ((ret = __log_vtruncate(dbenv,		    max_lsn, &((DB_TXNHEAD *)txninfo)->ckplsn, trunclsn)) != 0)			goto err;		/*		 * Now we need to open files that should be open in order for		 * client processing to continue.  However, since we've		 * truncated the log, we need to recompute from where the		 * openfiles pass should begin.		 */		if ((ret = __log_cursor(dbenv, &logc)) != 0)			goto err;		if ((ret =		    __log_c_get(logc, &first_lsn, &data, DB_FIRST)) != 0) {			if (ret == DB_NOTFOUND)				ret = 0;			else				__db_err(dbenv, "First log record not found");			goto err;		}		if ((ret = __txn_getckp(dbenv, &first_lsn)) == 0 &&		    (ret = __log_c_get(logc, &first_lsn, &data, DB_SET)) == 0) {			/* We have a recent checkpoint.  This is LSN (1). */			if ((ret = __txn_ckp_read(dbenv,			    data.data, &ckp_args)) != 0) {				__db_err(dbenv,			    "Invalid checkpoint record at [%ld][%ld]",				    (u_long)first_lsn.file,				    (u_long)first_lsn.offset);				goto err;			}			first_lsn = ckp_args->ckp_lsn;			__os_free(dbenv, ckp_args);		}		if ((ret = __log_c_get(logc, &first_lsn, &data, DB_SET)) != 0)			goto err;		if ((ret = __env_openfiles(dbenv, logc,		    txninfo, &data, &first_lsn, NULL, nfiles, 1)) != 0)			goto err;	} else if (region->stat.st_nrestores == 0)		/*		 * If there are no prepared transactions that need resolution,		 * we need to reset the transaction ID space and log this fact.		 */		if ((ret = __txn_reset(dbenv)) != 0)			goto err;	if (FLD_ISSET(dbenv->verbose, DB_VERB_RECOVERY)) {		(void)time(&now);		__db_msg(dbenv, "Recovery complete at %.24s", ctime(&now));		__db_msg(dbenv, "%s %lx %s [%lu][%lu]",		    "Maximum transaction ID",		    (u_long)(txninfo == NULL ?			TXN_MINIMUM : ((DB_TXNHEAD *)txninfo)->maxid),		    "Recovery checkpoint",		    (u_long)region->last_ckp.file,		    (u_long)region->last_ckp.offset);	}	if (0) {msgerr:		__db_err(dbenv,		    "Recovery function for LSN %lu %lu failed on %s pass",		    (u_long)lsn.file, (u_long)lsn.offset, pass);	}err:	if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0)		ret = t_ret;	if (txninfo != NULL)		__db_txnlist_end(dbenv, txninfo);	if (dtab != NULL)		__os_free(dbenv, dtab);	dbenv->tx_timestamp = 0;	F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);	F_CLR(region, TXN_IN_RECOVERY);	return (ret);}/* * Figure out how many logfiles we have processed.  If we are moving * forward (is_forward != 0), then we're computing current - low.  If * we are moving backward, we are computing high - current.  max is * the number of bytes per logfile. */static double__lsn_diff(low, high, current, max, is_forward)	DB_LSN *low, *high, *current;	u_int32_t max;	int is_forward;{	double nf;	/*	 * There are three cases in each direction.  If you are in the	 * same file, then all you need worry about is the difference in	 * offsets.  If you are in different files, then either your offsets	 * put you either more or less than the integral difference in the	 * number of files -- we need to handle both of these.	 */	if (is_forward) {		if (current->file == low->file)			nf = (double)(current->offset - low->offset) / max;		else if (current->offset < low->offset)			nf = (double)(current->file - low->file - 1) +			    (double)(max - low->offset + current->offset) / max;		else			nf = (double)(current->file - low->file) +			    (double)(current->offset - low->offset) / max;	} else {		if (current->file == high->file)			nf = (double)(high->offset - current->offset) / max;		else if (current->offset > high->offset)			nf = (double)(high->file - current->file - 1) +			    (double)			    (max - current->offset + high->offset) / max;		else			nf = (double)(high->file - current->file) +			    (double)(high->offset - current->offset) / max;	}	return (nf);}/* * __log_backup -- * * This is used to find the earliest log record to process when a client * is trying to sync up with a master whose max LSN is less than this * client's max lsn; we want to roll back everything after that. * Also used in the verify phase to walk back via checkpoints. * * Find the latest checkpoint whose ckp_lsn is less than the max lsn. * PUBLIC: int    __log_backup __P((DB_ENV *, DB_LOGC *, DB_LSN *, * PUBLIC:    DB_LSN *, u_int32_t)); */int__log_backup(dbenv, logc, max_lsn, start_lsn, cmp)	DB_ENV *dbenv;	DB_LOGC *logc;	DB_LSN *max_lsn, *start_lsn;	u_int32_t cmp;{	DB_LSN cmp_lsn, lsn;	DBT data;	__txn_ckp_args *ckp_args;	int lcmp, ret;	memset(&data, 0, sizeof(data));	ckp_args = NULL;	if (cmp != CKPLSN_CMP && cmp != LASTCKP_CMP)		return (EINVAL);	if ((ret = __txn_getckp(dbenv, &lsn)) != 0)		goto err;	/*	 * Cmp tells us whether to check the ckp_lsn or the last_ckp	 * fields in the checkpoint record.	 */	while ((ret = __log_c_get(logc, &lsn, &data, DB_SET)) == 0) {		if ((ret = __txn_ckp_read(dbenv, data.data, &ckp_args)) != 0)			return (ret);		if (cmp == CKPLSN_CMP) {			/*			 * Follow checkpoints through the log until			 * we find one with a ckp_lsn less than			 * or equal max_lsn.			 */			cmp_lsn = ckp_args->ckp_lsn;			lcmp = (log_compare(&cmp_lsn, max_lsn) <= 0);		} else {			/*			 * When we're walking back through the checkpoints			 * we want the LSN of this checkpoint strictly less			 * than the max_lsn (also a ckp LSN).			 */			cmp_lsn = lsn;			lcmp = (log_compare(&cmp_lsn, max_lsn) < 0);		}		if (lcmp) {			*start_lsn = cmp_lsn;			break;		}		lsn = ckp_args->last_ckp;		/*		 * If there are no more checkpoints behind us, we're		 * done.  Break with DB_NOTFOUND.		 */		if (IS_ZERO_LSN(lsn)) {			ret = DB_NOTFOUND;			break;		}		__os_free(dbenv, ckp_args);	}	if (ckp_args != NULL)		__os_free(dbenv, ckp_args);	/*	 * For CKPLSN_CMP if we walked back through all the checkpoints,	 * set the cursor on the first log record.  For LASTCKP_CMP	 * we want to return 0,0 in start_lsn.	 */err:	if (IS_ZERO_LSN(*start_lsn) && cmp == CKPLSN_CMP &&	    (ret == 0 || ret == DB_NOTFOUND))		ret = __log_c_get(logc, start_lsn, &data, DB_FIRST);	return (ret);}/* * __log_earliest -- * * Return the earliest recovery point for the log files present.  The * earliest recovery time is the time stamp of the first checkpoint record * whose checkpoint LSN is greater than the first LSN we process. */static int__log_earliest(dbenv, logc, lowtime, lowlsn)	DB_ENV *dbenv;	DB_LOGC *logc;	int32_t *lowtime;	DB_LSN *lowlsn;{	DB_LSN first_lsn, lsn;	DBT data;	__txn_ckp_args *ckpargs;	u_int32_t rectype;	int cmp, ret;	memset(&data, 0, sizeof(data));	/*	 * Read forward through the log looking for the first checkpoint	 * record whose ckp_lsn is greater than first_lsn.	 */	for (ret = __log_c_get(logc, &first_lsn, &data, DB_FIRST);	    ret == 0; ret = __log_c_get(logc, &lsn, &data, DB_NEXT)) {		memcpy(&rectype, data.data, sizeof(rectype));		if (rectype != DB___txn_ckp)			continue;		if ((ret = __txn_ckp_read(dbenv, data.data, &ckpargs)) == 0) {			cmp = log_compare(&ckpargs->ckp_lsn, &first_lsn);			*lowlsn = ckpargs->ckp_lsn;			*lowtime = ckpargs->timestamp;			__os_free(dbenv, ckpargs);			if (cmp >= 0)				break;		}	}	return (ret);}/* * __env_openfiles -- * Perform the pass of recovery that opens files.  This is used * both during regular recovery and an initial call to txn_recover (since * we need files open in order to abort prepared, but not yet committed * transactions). * * See the comments in db_apprec for a detailed description of the * various recovery passes. * * If we are not doing feedback processing (i.e., we are doing txn_recover * processing and in_recovery is zero), then last_lsn can be NULL. * * PUBLIC: int __env_openfiles __P((DB_ENV *, DB_LOGC *, * PUBLIC:     void *, DBT *, DB_LSN *, DB_LSN *, double, int)); */int__env_openfiles(dbenv, logc, txninfo,    data, open_lsn, last_lsn, nfiles, in_recovery)	DB_ENV *dbenv;	DB_LOGC *logc;	void *txninfo;	DBT *data;	DB_LSN *open_lsn, *last_lsn;	int in_recovery;	double nfiles;{	DB_LSN lsn, tlsn;	u_int32_t log_size;	int progress, ret;	/*	 * XXX	 * Get the log size.  No locking required because we're single-threaded	 * during recovery.	 */	log_size =	   ((LOG *)(((DB_LOG *)dbenv->lg_handle)->reginfo.primary))->log_size;	lsn = *open_lsn;	for (;;) {		if (in_recovery && dbenv->db_feedback != NULL) {			DB_ASSERT(last_lsn != NULL);			progress = (int)(33 * (__lsn_diff(open_lsn,			   last_lsn, &lsn, log_size, 1) / nfiles));			dbenv->db_feedback(dbenv, DB_RECOVER, progress);		}		tlsn = lsn;		ret = __db_dispatch(dbenv,		    dbenv->recover_dtab, dbenv->recover_dtab_size, data, &tlsn,		    in_recovery ? DB_TXN_OPENFILES : DB_TXN_POPENFILES,		    txninfo);		if (ret != 0 && ret != DB_TXN_CKP) {			__db_err(dbenv,			    "Recovery function for LSN %lu %lu failed",			    (u_long)lsn.file, (u_long)lsn.offset);			break;		}		if ((ret = __log_c_get(logc, &lsn, data, DB_NEXT)) != 0) {			if (ret == DB_NOTFOUND) {				if (last_lsn != NULL &&				   log_compare(&lsn, last_lsn) != 0)					ret = __db_log_corrupt(dbenv, &lsn);				else					ret = 0;			}			break;		}	}	return (ret);}static int__db_log_corrupt(dbenv, lsnp)	DB_ENV *dbenv;	DB_LSN *lsnp;{	__db_err(dbenv, "Log file corrupt at LSN: [%lu][%lu]",	     (u_long)lsnp->file, (u_long)lsnp->offset);	return (EINVAL);}

⌨️ 快捷键说明

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