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

📄 log_get.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
		}		nlsn.file = lp->lsn.file;		nlsn.offset = lp->lsn.offset - lp->len;		break;	case DB_SET:				/* Set log record. */		nlsn = *alsn;		break;	default:		DB_ASSERT(0);		ret = EINVAL;		goto err;	}	if (0) {				/* Move to the next file. */next_file:	++nlsn.file;		nlsn.offset = 0;	}	/*	 * The above switch statement should have set nlsn to the lsn of	 * the requested record.	 */	if (CRYPTO_ON(dbenv)) {		hdr.size = HDR_CRYPTO_SZ;		is_hmac = 1;	} else {		hdr.size = HDR_NORMAL_SZ;		is_hmac = 0;	}	/* Check to see if the record is in the cursor's buffer. */	if ((ret = __log_c_incursor(logc, &nlsn, &hdr, &rp)) != 0)		goto err;	if (rp != NULL)		goto cksum;	/*	 * Look to see if we're moving backward in the log with the last record	 * coming from the disk -- it means the record can't be in the region's	 * buffer.  Else, check the region's buffer.	 *	 * If the record isn't in the region's buffer, then either logs are	 * in-memory, and we're done, or  we're going to have to read the	 * record from disk.  We want to make a point of not reading past the	 * end of the logical log (after recovery, there may be data after the	 * end of the logical log, not to mention the log file may have been	 * pre-allocated).  So, zero out last_lsn, and initialize it inside	 * __log_c_inregion -- if it's still zero when we check it in	 * __log_c_ondisk, that's OK, it just means the logical end of the log	 * isn't an issue for this request.	 */	ZERO_LSN(last_lsn);	if (!F_ISSET(logc, DB_LOG_DISK) ||	    log_compare(&nlsn, &logc->c_lsn) > 0) {		F_CLR(logc, DB_LOG_DISK);		if ((ret = __log_c_inregion(logc,		    &nlsn, &rlock, &last_lsn, &hdr, &rp)) != 0)			goto err;		if (rp != NULL)			goto cksum;		if (lp->db_log_inmemory)			goto nohdr;	}	/*	 * We have to read from an on-disk file to retrieve the record.	 * If we ever can't retrieve the record at offset 0, we're done,	 * return EOF/DB_NOTFOUND.	 *	 * Discard the region lock if we're still holding it, the on-disk	 * reading routines don't need it.	 */	if (rlock == L_ACQUIRED) {		rlock = L_NONE;		R_UNLOCK(dbenv, &dblp->reginfo);	}	if ((ret = __log_c_ondisk(	    logc, &nlsn, &last_lsn, flags, &hdr, &rp, &eof)) != 0)		goto err;	if (eof) {		/*		 * Only DB_NEXT automatically moves to the next file, and		 * it only happens once.		 */		if (flags != DB_NEXT || nlsn.offset == 0)			return (DB_NOTFOUND);		goto next_file;	}	F_SET(logc, DB_LOG_DISK);cksum:	/*	 * Discard the region lock if we're still holding it.  (The path to	 * get here is that we acquired the lock because of the caller's	 * flag argument, but we found the record in the cursor's buffer.	 * Improbable, but it's easy to avoid.	 */	if (rlock == L_ACQUIRED) {		rlock = L_NONE;		R_UNLOCK(dbenv, &dblp->reginfo);	}	/*	 * Checksum: there are two types of errors -- a configuration error	 * or a checksum mismatch.  The former is always bad.  The latter is	 * OK if we're searching for the end of the log, and very, very bad	 * if we're reading random log records.	 */	db_cipher = dbenv->crypto_handle;	if ((ret = __db_check_chksum(dbenv, db_cipher,	    hdr.chksum, rp + hdr.size, hdr.len - hdr.size, is_hmac)) != 0) {		if (F_ISSET(logc, DB_LOG_SILENT_ERR)) {			if (ret == 0 || ret == -1)				ret = EIO;		} else if (ret == -1) {			__db_err(dbenv,		    "DB_LOGC->get: log record LSN %lu/%lu: checksum mismatch",			    (u_long)nlsn.file, (u_long)nlsn.offset);			__db_err(dbenv,		    "DB_LOGC->get: catastrophic recovery may be required");			ret = __db_panic(dbenv, DB_RUNRECOVERY);		}		goto err;	}	/*	 * If we got a 0-length record, that means we're in the midst of	 * some bytes that got 0'd as the result of a vtruncate.  We're	 * going to have to retry.	 */	if (hdr.len == 0) {nohdr:		switch (flags) {		case DB_FIRST:		case DB_NEXT:			/* Zero'd records always indicate the end of a file. */			goto next_file;		case DB_LAST:		case DB_PREV:			/*			 * We should never get here.  If we recover a log			 * file with 0's at the end, we'll treat the 0'd			 * headers as the end of log and ignore them.  If			 * we're reading backwards from another file, then			 * the first record in that new file should have its			 * prev field set correctly.			 */			__db_err(dbenv,		"Encountered zero length records while traversing backwards");			DB_ASSERT(0);			ret = __db_panic(dbenv, DB_RUNRECOVERY);			goto err;		case DB_SET:		default:			/* Return the 0-length record. */			break;		}	}	/* Copy the record into the user's DBT. */	if ((ret = __db_retcopy(dbenv, dbt, rp + hdr.size,	    (u_int32_t)(hdr.len - hdr.size),	    &logc->c_dbt.data, &logc->c_dbt.ulen)) != 0)		goto err;	if (CRYPTO_ON(dbenv)) {		if ((ret = db_cipher->decrypt(dbenv, db_cipher->data,		    hdr.iv, dbt->data, hdr.len - hdr.size)) != 0) {			ret = EAGAIN;			goto err;		}		/*		 * Return the original log record size to the user,		 * even though we've allocated more than that, possibly.		 * The log record is decrypted in the user dbt, not in		 * the buffer, so we must do this here after decryption,		 * not adjust the len passed to the __db_retcopy call.		 */		dbt->size = hdr.orig_size;	}	/* Update the cursor and the returned LSN. */	*alsn = nlsn;	logc->c_lsn = nlsn;	logc->c_len = hdr.len;	logc->c_prev = hdr.prev;err:	if (rlock == L_ACQUIRED)		R_UNLOCK(dbenv, &dblp->reginfo);	return (ret);}/* * __log_c_incursor -- *	Check to see if the requested record is in the cursor's buffer. */static int__log_c_incursor(logc, lsn, hdr, pp)	DB_LOGC *logc;	DB_LSN *lsn;	HDR *hdr;	u_int8_t **pp;{	u_int8_t *p;	int eof;	*pp = NULL;	/*	 * Test to see if the requested LSN could be part of the cursor's	 * buffer.	 *	 * The record must be part of the same file as the cursor's buffer.	 * The record must start at a byte offset equal to or greater than	 * the cursor buffer.	 * The record must not start at a byte offset after the cursor	 * buffer's end.	 */	if (logc->bp_lsn.file != lsn->file)		return (0);	if (logc->bp_lsn.offset > lsn->offset)		return (0);	if (logc->bp_lsn.offset + logc->bp_rlen <= lsn->offset + hdr->size)		return (0);	/*	 * Read the record's header and check if the record is entirely held	 * in the buffer.  If the record is not entirely held, get it again.	 * (The only advantage in having part of the record locally is that	 * we might avoid a system call because we already have the HDR in	 * memory.)	 *	 * If the header check fails for any reason, it must be because the	 * LSN is bogus.  Fail hard.	 */	p = logc->bp + (lsn->offset - logc->bp_lsn.offset);	memcpy(hdr, p, hdr->size);	if (__log_c_hdrchk(logc, lsn, hdr, &eof))		return (DB_NOTFOUND);	if (eof || logc->bp_lsn.offset + logc->bp_rlen < lsn->offset + hdr->len)		return (0);	*pp = p;				/* Success. */	return (0);}/* * __log_c_inregion -- *	Check to see if the requested record is in the region's buffer. */static int__log_c_inregion(logc, lsn, rlockp, last_lsn, hdr, pp)	DB_LOGC *logc;	DB_LSN *lsn, *last_lsn;	RLOCK *rlockp;	HDR *hdr;	u_int8_t **pp;{	DB_ENV *dbenv;	DB_LOG *dblp;	LOG *lp;	size_t b_region, len, nr;	u_int32_t b_disk;	int eof, ret;	u_int8_t *p;	dbenv = logc->dbenv;	dblp = dbenv->lg_handle;	lp = ((DB_LOG *)logc->dbenv->lg_handle)->reginfo.primary;	ret = 0;	b_region = 0;	*pp = NULL;	/* If we haven't yet acquired the log region lock, do so. */	if (*rlockp == L_NONE) {		*rlockp = L_ACQUIRED;		R_LOCK(dbenv, &dblp->reginfo);	}	/*	 * The routines to read from disk must avoid reading past the logical	 * end of the log, so pass that information back to it.	 *	 * Since they're reading directly from the disk, they must also avoid	 * reading past the offset we've written out.  If the log was	 * truncated, it's possible that there are zeroes or garbage on	 * disk after this offset, and the logical end of the log can	 * come later than this point if the log buffer isn't empty.	 */	*last_lsn = lp->lsn;	if (!lp->db_log_inmemory && last_lsn->offset > lp->w_off)		last_lsn->offset = lp->w_off;	/*	 * Test to see if the requested LSN could be part of the region's	 * buffer.	 *	 * During recovery, we read the log files getting the information to	 * initialize the region.  In that case, the region's lsn field will	 * not yet have been filled in, use only the disk.	 *	 * The record must not start at a byte offset after the region buffer's	 * end, since that means the request is for a record after the end of	 * the log.  Do this test even if the region's buffer is empty -- after	 * recovery, the log files may continue past the declared end-of-log,	 * and the disk reading routine will incorrectly attempt to read the	 * remainder of the log.	 *	 * Otherwise, test to see if the region's buffer actually has what we	 * want:	 *	 * The buffer must have some useful content.	 * The record must be in the same file as the region's buffer and must	 * start at a byte offset equal to or greater than the region's buffer.	 */	if (IS_ZERO_LSN(lp->lsn))		return (0);	if (log_compare(lsn, &lp->lsn) >= 0)		return (DB_NOTFOUND);	else if (lp->db_log_inmemory) {		if ((ret = __log_inmem_lsnoff(dblp, lsn, &b_region)) != 0)			return (ret);	} else if (lp->b_off == 0 || log_compare(lsn, &lp->f_lsn) < 0)		return (0);	/*	 * The current contents of the cursor's buffer will be useless for a	 * future call, we're about to overwrite it -- trash it rather than	 * try and make it look correct.	 */	logc->bp_rlen = 0;	/*	 * If the requested LSN is greater than the region buffer's first	 * byte, we know the entire record is in the buffer on a good LSN.	 *	 * If we're given a bad LSN, the "entire" record might not be in	 * our buffer in order to fail at the chksum.  __log_c_hdrchk made	 * sure our dest buffer fits, via bp_maxrec, but we also need to	 * make sure we don't run off the end of this buffer, the src.	 *	 * There is one case where the header check can fail: on a scan through	 * in-memory logs, when we reach the end of a file we can read an empty	 * heady.  In that case, it's safe to return zero, here: it will be	 * caught in our caller.  Otherwise, the LSN is bogus.  Fail hard.	 */	if (lp->db_log_inmemory || log_compare(lsn, &lp->f_lsn) > 0) {		if (!lp->db_log_inmemory)			b_region = lsn->offset - lp->w_off;		__log_inmem_copyout(dblp, b_region, hdr, hdr->size);		if (__log_c_hdrchk(logc, lsn, hdr, &eof) != 0)			return (DB_NOTFOUND);		if (eof)			return (0);		if (lp->db_log_inmemory) {			if (RINGBUF_LEN(lp, b_region, lp->b_off) < hdr->len)				return (DB_NOTFOUND);		} else if (lsn->offset + hdr->len > lp->w_off + lp->buffer_size)			return (DB_NOTFOUND);		if (logc->bp_size <= hdr->len) {			len = (size_t)DB_ALIGN(hdr->len * 2, 128);			if ((ret =			    __os_realloc(logc->dbenv, len, &logc->bp)) != 0)				 return (ret);			logc->bp_size = (u_int32_t)len;		}		__log_inmem_copyout(dblp, b_region, logc->bp, hdr->len);		*pp = logc->bp;		return (0);	}	DB_ASSERT(!lp->db_log_inmemory);	/*	 * There's a partial record, that is, the requested record starts	 * in a log file and finishes in the region buffer.  We have to	 * find out how many bytes of the record are in the region buffer	 * so we can copy them out into the cursor buffer.  First, check	 * to see if the requested record is the only record in the region	 * buffer, in which case we should copy the entire region buffer.	 *	 * Else, walk back through the region's buffer to find the first LSN	 * after the record that crosses the buffer boundary -- we can detect	 * that LSN, because its "prev" field will reference the record we	 * want.  The bytes we need to copy from the region buffer are the	 * bytes up to the record we find.  The bytes we'll need to allocate	 * to hold the log record are the bytes between the two offsets.	 */	b_disk = lp->w_off - lsn->offset;	if (lp->b_off <= lp->len)		b_region = (u_int32_t)lp->b_off;	else

⌨️ 快捷键说明

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