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

📄 scan.java

📁 derby database source code.good for you.
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*   Derby - Class org.apache.derby.impl.store.raw.log.Scan   Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.   Licensed under the Apache License, Version 2.0 (the "License");   you may not use this file except in compliance with the License.   You may obtain a copy of the License at      http://www.apache.org/licenses/LICENSE-2.0   Unless required by applicable law or agreed to in writing, software   distributed under the License is distributed on an "AS IS" BASIS,   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   See the License for the specific language governing permissions and   limitations under the License. */package org.apache.derby.impl.store.raw.log;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.services.io.ArrayInputStream;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.store.raw.log.LogInstant;import org.apache.derby.iapi.store.raw.xact.TransactionId;import org.apache.derby.impl.store.raw.log.LogCounter;import org.apache.derby.impl.store.raw.log.LogRecord;import org.apache.derby.impl.store.raw.log.StreamLogScan;import org.apache.derby.io.StorageRandomAccessFile;import java.io.IOException;import org.apache.derby.iapi.store.raw.Loggable;/**		Scan the the log which is implemented by a series of log files.n		This log scan knows how to move across log file if it is positioned at		the boundary of a log file and needs to getNextRecord.	<PRE>	4 bytes - length of user data, i.e. N	8 bytes - long representing log instant	N bytes of supplied data	4 bytes - length of user data, i.e. N	</PRE>*/public class Scan implements StreamLogScan {	// value for scanDirection	public static final byte FORWARD = 1;	public static final byte BACKWARD = 2;	public static final byte BACKWARD_FROM_LOG_END = 4;	private StorageRandomAccessFile scan;		// an output stream to the log file	private LogToFile logFactory; 		// log factory knows how to to skip										// from log file to log file	private long currentLogFileNumber; 	// the log file the scan is currently on	private long currentLogFileLength;	// the size of the current log file										// used only for FORWARD scan to determine when										// to switch the next log file	private long knownGoodLogEnd; // For FORWARD scan only								// during recovery, we need to determine the end								// of the log.  Everytime a complete log record								// is read in, knownGoodLogEnd is set to the								// log instant of the next log record if it is								// on the same log file.								// 								// only valid afer a successfull getNextRecord								// on a FOWARD scan. 	private long currentInstant;		// the log instant the scan is										// currently on - only valid after a										// successful getNextRecord	private long stopAt;				// scan until we find a log record whose 										// log instance < stopAt if we scan BACKWARD										// log instance > stopAt if we scan FORWARD										// log instance >= stopAt if we scan FORWARD_FLUSHED	private byte scanDirection; 		// BACKWARD or FORWARD	private boolean fuzzyLogEnd = false;   //get sets to true during forward scan 	                                      //for recovery, if there were	                                      //partial writes at the end of the log before crash;	                                      //during forward scan for recovery.	/**	    For backward scan, we expect a scan positioned at the end of the next log record.		For forward scan, we expect a scan positioned at the beginning of the next log record.		For forward flushed scan, we expect stopAt to be the instant for the		   first not-flushed log record. Like any forward scan, we expect a scan		   positioned at the beginning of the next log record.		@exception StandardException Standard Cloudscape error policy		@exception IOException cannot access the log at the new position.	*/	public Scan(LogToFile logFactory, long startAt, LogInstant stopAt, byte direction)		 throws IOException, StandardException	{		if (SanityManager.DEBUG)			SanityManager.ASSERT(startAt != LogCounter.INVALID_LOG_INSTANT, 								 "cannot start scan on an invalid log instant");		this.logFactory = logFactory;		currentLogFileNumber = LogCounter.getLogFileNumber(startAt);		currentLogFileLength = -1;		knownGoodLogEnd = LogCounter.INVALID_LOG_INSTANT;// set at getNextRecord for FORWARD scan		currentInstant = LogCounter.INVALID_LOG_INSTANT; // set at getNextRecord		if (stopAt != null)			this.stopAt = ((LogCounter) stopAt).getValueAsLong();		else			this.stopAt = LogCounter.INVALID_LOG_INSTANT;		switch(direction)		{		case FORWARD:			scan =  logFactory.getLogFileAtPosition(startAt);			scanDirection = FORWARD;			if (SanityManager.DEBUG)				if (scan == null)					SanityManager.THROWASSERT(						"scan null at " + LogCounter.toDebugString(startAt));			// NOTE: just get the length of the file without syncing.			// this only works because the only place forward scan is used			// right now is on recovery redo and nothing is being added to 			// the current log file.  When the forward scan is used for some			// other purpose, need to sync access to the end of the log			currentLogFileLength = scan.length();			break;		case BACKWARD:			// startAt is at the front of the log record, for backward			// scan we need to be positioned at the end of the log record			scan =  logFactory.getLogFileAtPosition(startAt);			int logsize = scan.readInt();			// skip forward over the log record and all the overhead, but remember			// we just read an int off the overhead			scan.seek(scan.getFilePointer() + logsize + LogToFile.LOG_RECORD_OVERHEAD - 4);			scanDirection = BACKWARD;			break;		case BACKWARD_FROM_LOG_END:			// startAt is at the end of the log, no need to skip the log record			scan =  logFactory.getLogFileAtPosition(startAt);			scanDirection = BACKWARD;			break;		}	}	/*	** Methods of StreamLogScan	*/	/**		Read the next log record.		Switching log to a previous log file if necessary, 		Resize the input stream byte array if necessary.  		@see StreamLogScan#getNextRecord		@return the next LogRecord, or null if the end of the		scan has been reached.		@exception StandardException Standard Cloudscape error policy	*/	public LogRecord getNextRecord(ArrayInputStream input, 							 TransactionId tranId, 							 int groupmask)		 throws StandardException	{		if (scan == null)			return null;		if (SanityManager.DEBUG)			SanityManager.ASSERT(scanDirection != 0, "scan has been secretly closed!");		LogRecord lr = null;		try		{			if (scanDirection == BACKWARD)				lr = getNextRecordBackward(input, tranId, groupmask);			else if (scanDirection == FORWARD)				lr = getNextRecordForward(input, tranId, groupmask);			return lr;		}		catch (IOException ioe)		{			if (SanityManager.DEBUG)				ioe.printStackTrace();			throw logFactory.markCorrupt(                StandardException.newException(SQLState.LOG_CORRUPTED, ioe));		}		catch (ClassNotFoundException cnfe)		{			if (SanityManager.DEBUG)				cnfe.printStackTrace();			throw logFactory.markCorrupt(                StandardException.newException(SQLState.LOG_CORRUPTED, cnfe));		}		finally		{			if (lr == null)				close();		// no more log record, close the scan		}	}	/**		Read the previous log record.		Switching log to a previous log file if necessary, 		Resize the input stream byte array if necessary.  		@see StreamLogScan#getNextRecord		Side effects include: 				on a successful read, setting currentInstant.				on a log file switch, setting currentLogFileNumber.		@return the previous LogRecord, or null if the end of the		scan has been reached.	*/	private LogRecord getNextRecordBackward(ArrayInputStream input, 									  TransactionId tranId,  									  int groupmask) 		 throws StandardException, IOException, ClassNotFoundException	{		if (SanityManager.DEBUG)			SanityManager.ASSERT(scanDirection == BACKWARD, "can only called by backward scan");		// scan is positioned just past the last byte of the record, or		// right at the beginning of the file (end of the file header)		// may need to switch log file		boolean candidate;		// if we have filtering, peek at the group and/or the transaction id,		// do them in one read rather than 2 reads.		int peekAmount = LogRecord.formatOverhead() + LogRecord.maxGroupStoredSize();		if (tranId != null)			peekAmount += LogRecord.maxTransactionIdStoredSize(tranId);		int readAmount;			// the number of bytes actually read		LogRecord lr;		long curpos = scan.getFilePointer();		do		{			// this log record is a candidate unless proven otherwise			candidate = true; 			lr = null;			readAmount = -1;			if (curpos == LogToFile.LOG_FILE_HEADER_SIZE)			{				// don't go thru the trouble of switching log file if we				// will have gone past stopAt				if (stopAt != LogCounter.INVALID_LOG_INSTANT &&					LogCounter.getLogFileNumber(stopAt) == currentLogFileNumber)				{					if (SanityManager.DEBUG)                    {                        if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))                        {                            SanityManager.DEBUG(LogToFile.DBG_FLAG,                                 "stopping at " + currentLogFileNumber);                        }                    }					return null;  // no more log record				}								// figure out where the last log record is in the previous				// log file				scan.seek(LogToFile.LOG_FILE_HEADER_PREVIOUS_LOG_INSTANT_OFFSET);				long previousLogInstant = scan.readLong();				scan.close();				if (SanityManager.DEBUG)				{					SanityManager.ASSERT(previousLogInstant != LogCounter.INVALID_LOG_INSTANT,									 "scanning backward beyond the first log file");					if (currentLogFileNumber != 							LogCounter.getLogFileNumber(previousLogInstant) + 1)						SanityManager.THROWASSERT(						"scanning backward but get incorrect log file number " + 						 "expected " + (currentLogFileNumber -1) + 						 "get " +						 LogCounter.getLogFileNumber(previousLogInstant));					SanityManager.ASSERT(LogCounter.getLogFilePosition(previousLogInstant) > 									 LogToFile.LOG_FILE_HEADER_SIZE,									 "scanning backward encounter completely empty log file");					SanityManager.DEBUG(LogToFile.DBG_FLAG, 									"scanning backwards from log file " +									currentLogFileNumber + ", switch to (" + 									LogCounter.getLogFileNumber(previousLogInstant) + "," +									LogCounter.getLogFilePosition(previousLogInstant) + ")"									);				}				// log file switch, set this.currentLogFileNumber				currentLogFileNumber = LogCounter.getLogFileNumber(previousLogInstant);				scan = logFactory.getLogFileAtPosition(previousLogInstant);				// scan is located right past the last byte of the last log				// record in the previous log file.  currentLogFileNumber is				// set.  We asserted that the scan is not located right at the				// end of the file header, in other words, there is at least				// one log record in this log file.				curpos = scan.getFilePointer();				// if the log file happens to be empty skip and proceed. 				// ideally this case should never occur because log switch is				// not suppose to happen on an empty log file. 				// But it is safer to put following check incase if it ever				// happens to avoid any recovery issues. 				if (curpos == LogToFile.LOG_FILE_HEADER_SIZE)					continue;			}			scan.seek(curpos - 4);			int recordLength = scan.readInt(); // get the length after the log record			// calculate where this log record started.			// include the eight bytes for the long log instant at the front			// the four bytes of length in the front and the four bytes we just read			long recordStartPosition = curpos - recordLength -				LogToFile.LOG_RECORD_OVERHEAD; 			if (SanityManager.DEBUG)			{				if (recordStartPosition < LogToFile.LOG_FILE_HEADER_SIZE)					SanityManager.THROWASSERT(								 "next position " + recordStartPosition +								 " recordLength " + recordLength + 								 " current file position " + scan.getFilePointer());				scan.seek(recordStartPosition);				// read the length before the log record and check it against the				// length after the log record				int checkLength = scan.readInt();				if (checkLength != recordLength)				{					long inst = LogCounter.makeLogInstantAsLong(currentLogFileNumber, recordStartPosition);					throw logFactory.markCorrupt(                        StandardException.newException(                            SQLState.LOG_RECORD_CORRUPTED,                             new Long(checkLength),                            new Long(recordLength),                            new Long(inst),                            new Long(currentLogFileNumber)));				}			}			else			{				// skip over the length in insane				scan.seek(recordStartPosition+4);			}			// scan is positioned just before the log instant			// read the current log instant - this is the currentInstant if we have not			// exceeded the scan limit			currentInstant = scan.readLong();			if (SanityManager.DEBUG)			{				// sanity check the current instant against the scan position				if (LogCounter.getLogFileNumber(currentInstant) !=					currentLogFileNumber ||					LogCounter.getLogFilePosition(currentInstant) !=					recordStartPosition)					SanityManager.THROWASSERT(								 "Wrong LogInstant on log record " +								LogCounter.toDebugString(currentInstant) + 								 " version real position (" +								 currentLogFileNumber + "," +								 recordStartPosition + ")");			}			// if stopAt == INVALID_LOG_INSTANT, no stop instant, read till

⌨️ 快捷键说明

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