📄 scan.java
字号:
// nothing more can be read. Else check scan limit if (currentInstant < stopAt && stopAt != LogCounter.INVALID_LOG_INSTANT) { currentInstant = LogCounter.INVALID_LOG_INSTANT; return null; // we went past the stopAt } byte[] data = input.getData(); if (data.length < recordLength) { // make a new array of sufficient size and reset the arrary // in the input stream data = new byte[recordLength]; input.setData(data); } // If the log is encrypted, we must do the filtering after reading // and decrypting the record. if (logFactory.databaseEncrypted()) { scan.readFully(data, 0, recordLength); int len = logFactory.decrypt(data, 0, recordLength, data, 0); if (SanityManager.DEBUG) SanityManager.ASSERT(len == recordLength); input.setLimit(0, recordLength); } 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(); // skip the checksum log records, there is no need to look at them // during backward scans. They are used only in forwardscan during recovery. if(lr.isChecksum()) { candidate = false; }else if (groupmask != 0 || tranId != null) { // skip the checksum log records if(lr.isChecksum()) candidate = false; if (candidate && 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); } } } // go back to the start of the log record so that the next time // this method is called, it is positioned right past the last byte // of the record. curpos = recordStartPosition; scan.seek(curpos); } while (candidate == false); return lr; } /** 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 Side effects include: on a successful read, setting currentInstant, knownGoodLogEnd on a log file switch, setting currentLogFileNumber, currentLogFileLength. on detecting a fuzzy log end that needs clearing, it will call logFactory to clear the fuzzy log end. @return the next LogRecord, or null if the end of the scan has been reached. */ private LogRecord getNextRecordForward(ArrayInputStream input, TransactionId tranId, int groupmask) throws StandardException, IOException, ClassNotFoundException { if (SanityManager.DEBUG) SanityManager.ASSERT(scanDirection == FORWARD, "can only called by forward scan"); // NOTE: // // if forward scan, scan is positioned at the first byte of the // next record, or the end of file - note the the 'end of file' // is defined at the time the scan is initialized. If we are // on the current log file, it may well have grown by now... // // This is not a problem in reality because the only forward // scan on the log now is recovery redo and the log does not // grow. If in the future, a foward scan of the log is used // for some other reasons, need to keep this in mind. // // first we need to make sure the entire log record is on the // log, or else this is a fuzzy log end. // RESOLVE: can get this from knownGoodLogEnd if this is not the first // time getNext is called. Probably just as fast to call // scan.getFilePointer though... long recordStartPosition = scan.getFilePointer(); 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; do { // this log record is a candidate unless proven otherwise candidate = true; lr = null; readAmount = -1; // if we are not right at the end but this position + 4 is at // or exceeds the end, we know we don't have a complete log // record. This is the log file and chalk it up as the fuzzy // end. if (recordStartPosition + 4 > currentLogFileLength) { // since there is no end of log file marker, we are at the // end of the log. if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "detected fuzzy log end on log file " + currentLogFileNumber + " record start position " + recordStartPosition + " file length " + currentLogFileLength); } } //if recordStartPosition == currentLogFileLength //there is NO fuzz, it just a properly ended log //without the end marker. if(recordStartPosition != currentLogFileLength) fuzzyLogEnd = true ; // don't bother to write the end of log file marker because // if it is not overwritten by the next log record then // the next time the database is recovered it will come // back right here return null; } // read in the length before the log record int recordLength = scan.readInt(); while (recordLength == 0 || recordStartPosition + recordLength + LogToFile.LOG_RECORD_OVERHEAD > currentLogFileLength) { // if recordLength is zero or the log record goes beyond the // current file, then we have detected the end of a log file. // // If recordLength == 0 then we know that this log file has either // been properly switched or it had a 1/2 written log record which // was subsequently cleared by clearFuzzyEnd. // // If recordLength != 0 but log record goes beyond the current log // file, we have detected a fuzzy end. This is the last log file // since we will clear it by clearFuzzyEnd. if (recordLength != 0) // this is a fuzzy log end { if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG( LogToFile.DBG_FLAG, "detected fuzzy log end on log file " + currentLogFileNumber + " record start position " + recordStartPosition + " file length " + currentLogFileLength + " recordLength=" + recordLength ); } } fuzzyLogEnd = true; scan.close(); scan = null; return null; } // recordLength == 0 if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { if (recordStartPosition + 4 == currentLogFileLength) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "detected proper log end on log file " + currentLogFileNumber); } else { SanityManager.DEBUG(LogToFile.DBG_FLAG, "detected zapped log end on log file " + currentLogFileNumber + " end marker at " + recordStartPosition + " real end at " + currentLogFileLength); } } } // don't go thru the trouble of switching log file if we // have will have gone past stopAt if we want to stop here if (stopAt != LogCounter.INVALID_LOG_INSTANT && LogCounter.getLogFileNumber(stopAt) == currentLogFileNumber) { return null; } // // we have a log end marker and we don't want to stop yet, switch // log file // scan.close(); // set this.currentLogFileNumber scan = logFactory.getLogFileAtBeginning(++currentLogFileNumber); if (scan == null) // we have seen the last log file { return null; } if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "switched to next log file " + currentLogFileNumber); } } // scan is position just past the log header recordStartPosition = scan.getFilePointer(); // set this.currentLogFileLength currentLogFileLength = scan.length(); if (recordStartPosition+4 >= currentLogFileLength) // empty log file { if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) { SanityManager.DEBUG(LogToFile.DBG_FLAG, "log file " + currentLogFileNumber + " is empty"); } } // ideally, we would want to start writing on this new // empty log file, but the scan is closed and there is // no way to tell the difference between an empty log // file and a log file which is not there. We will be // writing to the end of the previous log file instead // but when we next switch the log, the empty log file // will be written over. return null; } // we have successfully switched to the next log file. // scan is positioned just before the next log record // see if this one is written in entirety recordLength = scan.readInt(); } // we know the entire log record is on this log file // read the current log instant currentInstant = scan.readLong(); /*check if the current instant happens is less than the last one. *This can happen if system crashed before writing the log instant *completely. If the instant is partially written it will be less *than the last one and should be the last record that was suppose to *get written. Currentlt preallocated files are filled with zeros, *this should hold good. *Note: In case of Non-preallocated files earlier 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. */ if(currentInstant < knownGoodLogEnd) { fuzzyLogEnd = true ; return null; } // sanity check it if (SanityManager.DEBUG) { 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 // nothing more can be read. Else check scan limit if (stopAt != LogCounter.INVALID_LOG_INSTANT && currentInstant > stopAt) { currentInstant = LogCounter.INVALID_LOG_INSTANT; return null; // we went past the stopAt } // read in the log record byte[] data = input.getData(); if (data.length < recordLength) { // make a new array of sufficient size and reset the arrary // in the input stream data = new byte[recordLength]; input.setData(data); } // If the log is encrypted, we must do the filtering after // reading and decryptiong the record. if (logFactory.databaseEncrypted()) { scan.readFully(data, 0, recordLength); int len = logFactory.decrypt(data, 0, recordLength, data, 0); if (SanityManager.DEBUG) SanityManager.ASSERT(len == recordLength); input.setLimit(0, len); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -