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

📄 log_get.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996-2002 *	Sleepycat Software.  All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: log_get.c,v 11.81 2002/08/14 20:09:27 bostic Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <string.h>#include <unistd.h>#endif#include "db_int.h"#include "dbinc/crypto.h"#include "dbinc/db_page.h"#include "dbinc/hmac.h"#include "dbinc/log.h"#include "dbinc/hash.h"typedef enum { L_ALREADY, L_ACQUIRED, L_NONE } RLOCK;static int __log_c_close __P((DB_LOGC *, u_int32_t));static int __log_c_get __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t));static int __log_c_get_int __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t));static int __log_c_hdrchk __P((DB_LOGC *, HDR *, int *));static int __log_c_incursor __P((DB_LOGC *, DB_LSN *, HDR *, u_int8_t **));static int __log_c_inregion __P((DB_LOGC *,	       DB_LSN *, RLOCK *, DB_LSN *, HDR *, u_int8_t **));static int __log_c_io __P((DB_LOGC *,	       u_int32_t, u_int32_t, void *, size_t *, int *));static int __log_c_ondisk __P((DB_LOGC *,	       DB_LSN *, DB_LSN *, int, HDR *, u_int8_t **, int *));static int __log_c_set_maxrec __P((DB_LOGC *, char *));static int __log_c_shortread __P((DB_LOGC *, int));/* * __log_cursor -- *	Create a log cursor. * * PUBLIC: int __log_cursor __P((DB_ENV *, DB_LOGC **, u_int32_t)); */int__log_cursor(dbenv, logcp, flags)	DB_ENV *dbenv;	DB_LOGC **logcp;	u_int32_t flags;{	DB_LOGC *logc;	int ret;	PANIC_CHECK(dbenv);	ENV_REQUIRES_CONFIG(dbenv,	    dbenv->lg_handle, "DB_ENV->log_cursor", DB_INIT_LOG);	*logcp = NULL;	/* Validate arguments. */	if ((ret = __db_fchk(dbenv, "DB_ENV->log_cursor", flags, 0)) != 0)		return (ret);	/* Allocate memory for the cursor. */	if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOGC), &logc)) != 0)		goto err;	if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), &logc->c_fh)) != 0)		goto err;	logc->bp_size = DB_LOGC_BUF_SIZE;	if ((ret = __os_malloc(dbenv, logc->bp_size, &logc->bp)) != 0)		goto err;	logc->dbenv = dbenv;	logc->close = __log_c_close;	logc->get = __log_c_get;	*logcp = logc;	return (0);err:	if (logc != NULL) {		if (logc->c_fh != NULL)			__os_free(dbenv, logc->c_fh);		__os_free(dbenv, logc);	}	return (ret);}/* * __log_c_close -- *	Close a log cursor. */static int__log_c_close(logc, flags)	DB_LOGC *logc;	u_int32_t flags;{	DB_ENV *dbenv;	int ret;	dbenv = logc->dbenv;	PANIC_CHECK(dbenv);	if ((ret = __db_fchk(dbenv, "DB_LOGC->close", flags, 0)) != 0)		return (ret);	if (F_ISSET(logc->c_fh, DB_FH_VALID))		(void)__os_closehandle(dbenv, logc->c_fh);	if (logc->c_dbt.data != NULL)		__os_free(dbenv, logc->c_dbt.data);	__os_free(dbenv, logc->bp);	__os_free(dbenv, logc->c_fh);	__os_free(dbenv, logc);	return (0);}/* * __log_c_get -- *	Get a log record. */static int__log_c_get(logc, alsn, dbt, flags)	DB_LOGC *logc;	DB_LSN *alsn;	DBT *dbt;	u_int32_t flags;{	DB_ENV *dbenv;	DB_LSN saved_lsn;	int ret;	dbenv = logc->dbenv;	PANIC_CHECK(dbenv);	/* Validate arguments. */	switch (flags) {	case DB_CURRENT:	case DB_FIRST:	case DB_LAST:	case DB_NEXT:	case DB_PREV:		break;	case DB_SET:		if (IS_ZERO_LSN(*alsn)) {			__db_err(dbenv, "DB_LOGC->get: invalid LSN");			return (EINVAL);		}		break;	default:		return (__db_ferr(dbenv, "DB_LOGC->get", 1));	}	/*	 * On error, we take care not to overwrite the caller's LSN.  This	 * is because callers looking for the end of the log loop using the	 * DB_NEXT flag, and expect to take the last successful lsn out of	 * the passed-in structure after DB_LOGC->get fails with DB_NOTFOUND.	 *	 * !!!	 * This line is often flagged an uninitialized memory read during a	 * Purify or similar tool run, as the application didn't initialize	 * *alsn.  If the application isn't setting the DB_SET flag, there is	 * no reason it should have initialized *alsn, but we can't know that	 * and we want to make sure we never overwrite whatever the application	 * put in there.	 */	saved_lsn = *alsn;	/*	 * If we get one of the log's header records as a result of doing a	 * DB_FIRST, DB_NEXT, DB_LAST or DB_PREV, repeat the operation, log	 * file header records aren't useful to applications.	 */	if ((ret = __log_c_get_int(logc, alsn, dbt, flags)) != 0) {		*alsn = saved_lsn;		return (ret);	}	if (alsn->offset == 0 && (flags == DB_FIRST ||	    flags == DB_NEXT || flags == DB_LAST || flags == DB_PREV)) {		switch (flags) {		case DB_FIRST:			flags = DB_NEXT;			break;		case DB_LAST:			flags = DB_PREV;			break;		}		if (F_ISSET(dbt, DB_DBT_MALLOC)) {			__os_free(dbenv, dbt->data);			dbt->data = NULL;		}		if ((ret = __log_c_get_int(logc, alsn, dbt, flags)) != 0) {			*alsn = saved_lsn;			return (ret);		}	}	return (0);}/* * __log_c_get_int -- *	Get a log record; internal version. */static int__log_c_get_int(logc, alsn, dbt, flags)	DB_LOGC *logc;	DB_LSN *alsn;	DBT *dbt;	u_int32_t flags;{	DB_CIPHER *db_cipher;	DB_ENV *dbenv;	DB_LOG *dblp;	DB_LSN last_lsn, nlsn;	HDR hdr;	LOG *lp;	RLOCK rlock;	logfile_validity status;	u_int32_t cnt;	u_int8_t *rp;	int eof, is_hmac, ret;	dbenv = logc->dbenv;	dblp = dbenv->lg_handle;	lp = dblp->reginfo.primary;	is_hmac = 0;	/*	 * We don't acquire the log region lock until we need it, and we	 * release it as soon as we're done.	 */	rlock = F_ISSET(logc, DB_LOG_LOCKED) ? L_ALREADY : L_NONE;	nlsn = logc->c_lsn;	switch (flags) {	case DB_NEXT:				/* Next log record. */		if (!IS_ZERO_LSN(nlsn)) {			/* Increment the cursor by the cursor record size. */			nlsn.offset += logc->c_len;			break;		}		flags = DB_FIRST;		/* FALLTHROUGH */	case DB_FIRST:				/* First log record. */		/* Find the first log file. */		if ((ret = __log_find(dblp, 1, &cnt, &status)) != 0)			goto err;		/*		 * DB_LV_INCOMPLETE:		 *	Theoretically, the log file we want could be created		 *	but not yet written, the "first" log record must be		 *	in the log buffer.		 * DB_LV_NORMAL:		 * DB_LV_OLD_READABLE:		 *	We found a log file we can read.		 * DB_LV_NONEXISTENT:		 *	No log files exist, the "first" log record must be in		 *	the log buffer.		 * DB_LV_OLD_UNREADABLE:		 *	No readable log files exist, we're at the cross-over		 *	point between two versions.  The "first" log record		 *	must be in the log buffer.		 */		switch (status) {		case DB_LV_INCOMPLETE:			DB_ASSERT(lp->lsn.file == cnt);			/* FALLTHROUGH */		case DB_LV_NORMAL:		case DB_LV_OLD_READABLE:			nlsn.file = cnt;			break;		case DB_LV_NONEXISTENT:			nlsn.file = 1;			DB_ASSERT(lp->lsn.file == nlsn.file);			break;		case DB_LV_OLD_UNREADABLE:			nlsn.file = cnt + 1;			DB_ASSERT(lp->lsn.file == nlsn.file);			break;		}		nlsn.offset = 0;		break;	case DB_CURRENT:			/* Current log record. */		break;	case DB_PREV:				/* Previous log record. */		if (!IS_ZERO_LSN(nlsn)) {			/* If at start-of-file, move to the previous file. */			if (nlsn.offset == 0) {				if (nlsn.file == 1 ||				    __log_valid(dblp,					nlsn.file - 1, 0, &status) != 0) {					ret = DB_NOTFOUND;					goto err;				}				if (status != DB_LV_NORMAL &&				    status != DB_LV_OLD_READABLE) {					ret = DB_NOTFOUND;					goto err;				}				--nlsn.file;			}			nlsn.offset = logc->c_prev;			break;		}		/* FALLTHROUGH */	case DB_LAST:				/* Last log record. */		if (rlock == L_NONE) {			rlock = L_ACQUIRED;			R_LOCK(dbenv, &dblp->reginfo);		}		nlsn.file = lp->lsn.file;		nlsn.offset = lp->lsn.offset - lp->len;		break;	case DB_SET:				/* Set log record. */		nlsn = *alsn;		break;	}	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, 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;	}	/*	 * 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 == 1) {		/*		 * 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 checksum mismatch");			__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) {		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);		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;	*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.	 */

⌨️ 快捷键说明

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