📄 scan.java
字号:
else // no need to decrypt, only get the group and tid if we filter { if (groupmask == 0 && tranId == null) { // no filter, get the whole thing scan.readFully(data, 0, recordLength); input.setLimit(0, recordLength); } else { // Read only enough so that group and the tran id is in // the data buffer. Group is stored as compressed int // and tran id is stored as who knows what. read min // of peekAmount or recordLength readAmount = (recordLength > peekAmount) ? peekAmount : recordLength; // in the data buffer, we now have enough to peek scan.readFully(data, 0, readAmount); input.setLimit(0, readAmount); } } lr = (LogRecord) input.readObject(); if (groupmask != 0 || tranId != null) { if (groupmask != 0 && (groupmask & lr.group()) == 0) candidate = false; // no match, throw this log record out if (candidate && tranId != null) { TransactionId tid = lr.getTransactionId(); if (!tid.equals(tranId)) // nomatch candidate = false; // throw this log record out } // if this log record is not filtered out, we need to read // in the rest of the log record to the input buffer. // Except if it is an encrypted database, in which case the // entire log record have already be read in for // decryption. if (candidate && !logFactory.databaseEncrypted()) { // read the rest of the log into the buffer if (SanityManager.DEBUG) SanityManager.ASSERT(readAmount > 0); if (readAmount < recordLength) { // Need to remember where we are because the log // record may have read part of it off the input // stream already and that position is lost when we // set limit again. int inputPosition = input.getPosition(); scan.readFully(data, readAmount, recordLength-readAmount); input.setLimit(0, recordLength); input.setPosition(inputPosition); } } } /*check if the logrecord length written before and after the *log record are equal, if not the end of of the log is reached. *This can happen if system crashed before writing the length field *in the end of the records completely. If the length is partially *written or not written at all it will not match with length written *in the beginning of the log record. Currentlt preallocated files *are filled with zeros, log record length can never be zero; *if the lengths are not matching, end of the properly written log *is reached. *Note: In case of Non-preallocated files earlier fuzzy case check with log * file lengths should have found the end. But in prellocated files, log file *length is not sufficiant to find the log end. This check *is must to find the end in preallocated log files. */ // read the length after the log record and check it against the // length before the log record, make sure we go to the correct // place for skipped log record. if (!candidate) scan.seek(recordStartPosition - 4); int checkLength = scan.readInt(); if (checkLength != recordLength && checkLength < recordLength) { //lengh written in the end of the log record should be always //less then the length written in the beginning if the log //record was half written before the crash. if(checkLength < recordLength) { fuzzyLogEnd = true ; return null; }else { //If checklength > recordLength then it can be not be a partial write //probablly it is corrupted for some reason , this should never //happen throw error in debug mode. In non debug case , let's //hope it's only is wrong and system can proceed. if (SanityManager.DEBUG) { throw logFactory.markCorrupt (StandardException.newException( SQLState.LOG_RECORD_CORRUPTED, new Long(checkLength), new Long(recordLength), new Long(currentInstant), new Long(currentLogFileNumber))); } //In non debug case, do nothing , let's hope it's only //length part that is incorrect and system can proceed. } } // next record start position is right after this record recordStartPosition += recordLength + LogToFile.LOG_RECORD_OVERHEAD; knownGoodLogEnd = LogCounter.makeLogInstantAsLong (currentLogFileNumber, recordStartPosition); if (SanityManager.DEBUG) { if (recordStartPosition != scan.getFilePointer()) SanityManager.THROWASSERT( "calculated end " + recordStartPosition + " != real end " + scan.getFilePointer()); } else { // seek to the start of the next log record scan.seek(recordStartPosition); } // the scan is now positioned just past this log record and right // at the beginning of the next log record /** if the current log record is a checksum log record then * using the information available in this record validate * that data in the log file by matching the checksum in * checksum log record and by recalculating the checksum for the * specified length of the data in the log file. cheksum values * should match unless the right was incomplete before the crash. */ if(lr.isChecksum()) { // checksum log record should not be returned to the logger recovery redo // routines, it is just used to identify the incomplete log writes. candidate = false; Loggable op = lr.getLoggable(); if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY) || SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) SanityManager.DEBUG(LogToFile.DBG_FLAG, "scanned " + "Null" + " : " + op + " instant = " + LogCounter.toDebugString(currentInstant) + " logEnd = " + LogCounter.toDebugString(knownGoodLogEnd)); } ChecksumOperation clop = (ChecksumOperation) op; int ckDataLength = clop.getDataLength(); // resize the buffer to be size of checksum data length if required. if (data.length < ckDataLength) { // make a new array of sufficient size and reset the arrary // in the input stream data = new byte[ckDataLength]; input.setData(data); input.setLimit(0, ckDataLength); } boolean validChecksum = false; // check if the expected number of bytes by the checksum log // record actually exist in the file and then verify if checksum // is valid to identify any incomplete out of order writes. if((recordStartPosition + ckDataLength) <= currentLogFileLength) { // read the data into the buffer scan.readFully(data, 0, ckDataLength); // verify the checksum if(clop.isChecksumValid(data, 0 , ckDataLength)) validChecksum = true; } if(!validChecksum) { // declare that the end of the transaction log is fuzzy, checksum is invalid // only when the writes are incomplete; this can happen // only when writes at the end of the log were partially // written before the crash. if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG( LogToFile.DBG_FLAG, "detected fuzzy log end on log file while doing checksum checks " + currentLogFileNumber + " checksum record start position " + recordStartPosition + " file length " + currentLogFileLength + " checksumDataLength=" + ckDataLength); } } fuzzyLogEnd = true; scan.close(); scan = null; return null; } // reset the scan to the start of the next log record scan.seek(recordStartPosition); } } while (candidate == false) ; return lr; } /** Reset the scan to the given LogInstant. @param instant the position to reset to @exception IOException scan cannot access the log at the new position. @exception StandardException cloudscape standard error policy */ public void resetPosition(LogInstant instant) throws IOException, StandardException { if (SanityManager.DEBUG) SanityManager.ASSERT(instant != null); long instant_long = ((LogCounter)instant).getValueAsLong(); if ((instant_long == LogCounter.INVALID_LOG_INSTANT) || (stopAt != LogCounter.INVALID_LOG_INSTANT && (scanDirection == FORWARD && instant_long > stopAt) || (scanDirection == FORWARD && instant_long < stopAt))) { close(); throw StandardException.newException( SQLState.LOG_RESET_BEYOND_SCAN_LIMIT, instant, new LogCounter(stopAt)); } else { long fnum = ((LogCounter)instant).getLogFileNumber(); if (fnum != currentLogFileNumber) { if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "Scan " + scanDirection + " resetting to " + instant + " need to switch log from " + currentLogFileNumber + " to " + fnum); } } scan.close(); scan = logFactory.getLogFileAtPosition(instant_long); currentLogFileNumber= fnum; if (scanDirection == FORWARD) { // 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(); } } else { long fpos = ((LogCounter)instant).getLogFilePosition(); scan.seek(fpos); // //RESOLVE: Can this be optimized? Does it belong here. currentLogFileLength = scan.length(); if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "Scan reset to " + instant); } } } currentInstant = instant_long; //scan is being reset, it is possibly that, scan is doing a random //access of the log file. set the knownGoodLogEnd to the instant //scan is being reset to. //Note: reset gets called with undo forward scan for CLR processing during //recovery, if this value is not reset checks to find the end of log //getNextRecordForward() will fail because undoscan scans log file //back & forth to redo CLR's. knownGoodLogEnd = currentInstant; if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "Scan.getInstant reset to " + currentInstant + LogCounter.toDebugString(currentInstant)); } } } } /** Return the log instant (as an integer) the scan is currently on - this is the log instant of the log record that was returned by getNextRecord. */ public long getInstant() { return currentInstant; } /** Return the log instant at the end of the log record on the current LogFile in the form of a log instant */ public long getLogRecordEnd() { return knownGoodLogEnd; } /** returns true if there is partially writen log records before the crash in the last log file. Partiall wrires are identified during forward redo scans for log recovery. */ public boolean isLogEndFuzzy() { return fuzzyLogEnd; } /** Return the log instant the scan is currently on - this is the log instant of the log record that was returned by getNextRecord. */ public LogInstant getLogInstant() { if (currentInstant == LogCounter.INVALID_LOG_INSTANT) return null; else return new LogCounter(currentInstant); } /** Close the scan. */ public void close() { if (scan != null) { try { scan.close(); } catch (IOException ioe) {} scan = null; } logFactory = null; currentLogFileNumber = -1; currentLogFileLength = -1; knownGoodLogEnd = LogCounter.INVALID_LOG_INSTANT; currentInstant = LogCounter.INVALID_LOG_INSTANT; stopAt = LogCounter.INVALID_LOG_INSTANT; scanDirection = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -