Author: mikem Date: Sat Mar 17 16:22:36 2012 New Revision: 1301955 URL: http://svn.apache.org/viewvc?rev=1301955&view=rev Log: DERBY-2254 Assert during log file switch: log file position exceeded max log file size backport change #1102417 from trunk to 10.6 branch. Increase overhead requirements which trigger log file switches when the checkpointing thread can't keep up with log writers. Modified: db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogCounter.java db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java Modified: db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java?rev=1301955&r1=1301954&r2=1301955&view=diff ============================================================================== --- db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java (original) +++ db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java Sat Mar 17 16:22:36 2012 @@ -933,6 +933,9 @@ public class LogAccessFile } + /** Return the length of a checksum record */ + public int getChecksumLogRecordSize() { return checksumLogRecordSize; } + protected void writeEndMarker(int marker) throws IOException, StandardException { Modified: db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogCounter.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogCounter.java?rev=1301955&r1=1301954&r2=1301955&view=diff ============================================================================== --- db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogCounter.java (original) +++ db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogCounter.java Sat Mar 17 16:22:36 2012 @@ -90,9 +90,9 @@ public class LogCounter implements LogIn SanityManager.ASSERT(position > 0, "illegal file position"); SanityManager.ASSERT(position < MAX_LOGFILE_SIZE, - "log file position exceeded max log file size"); + "log file position exceeded max log file size. log file position = " + position ); SanityManager.ASSERT(fileNumber < MAX_LOGFILE_NUMBER, - "log file number exceeded max log file number"); + "log file number exceeded max log file number. log file number = " + fileNumber ); } this.fileNumber = fileNumber; @@ -118,9 +118,9 @@ public class LogCounter implements LogIn SanityManager.ASSERT(filepos > 0, "illegal file position"); SanityManager.ASSERT(filepos < MAX_LOGFILE_SIZE, - "log file position exceeded max log file size"); + "log file position exceeded max log file size. log file position = " + filepos ); SanityManager.ASSERT(filenum < MAX_LOGFILE_NUMBER, - "log file number exceeded max log file number"); + "log file number exceeded max log file number. log file number = " + filenum ); } return ((filenum << FILE_NUMBER_SHIFT) | filepos); Modified: db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java?rev=1301955&r1=1301954&r2=1301955&view=diff ============================================================================== --- db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java (original) +++ db/derby/code/branches/10.6/java/engine/org/apache/derby/impl/store/raw/log/LogToFile.java Sat Mar 17 16:22:36 2012 @@ -221,6 +221,8 @@ public final class LogToFile implements Serviceable, java.security.PrivilegedExceptionAction { + private static final long INT_LENGTH = 4L; + private static int fid = StoredFormatIds.FILE_STREAM_LOG_FILE; // format Id must fit in 4 bytes @@ -1028,7 +1030,7 @@ public final class LogToFile implements // successfully init'd the log file - set up markers, // and position at the end of the log. - endPosition = theLog.getFilePointer(); + setEndPosition( theLog.getFilePointer() ); lastFlush = endPosition; //if write sync is true , prellocate the log file @@ -1099,7 +1101,7 @@ public final class LogToFile implements if (!ReadOnlyDB) { - endPosition = LogCounter.getLogFilePosition(logEnd); + setEndPosition( LogCounter.getLogFilePosition(logEnd) ); // // The end of the log is at endPosition. Which is where @@ -2094,7 +2096,7 @@ public final class LogToFile implements logOut.writeEndMarker(0); - endPosition += 4; + setEndPosition( endPosition + INT_LENGTH ); //set that we are in log switch to prevent flusher //not requesting to switch log again inLogSwitch = true; @@ -2114,7 +2116,7 @@ public final class LogToFile implements logWrittenFromLastCheckPoint += endPosition; - endPosition = newLog.getFilePointer(); + setEndPosition( newLog.getFilePointer() ); lastFlush = endPosition; if(isWriteSynced) @@ -3376,7 +3378,7 @@ public final class LogToFile implements SQLState.LOG_SEGMENT_NOT_EXIST, logFile.getPath()); } - endPosition = firstLog.getFilePointer(); + setEndPosition( firstLog.getFilePointer() ); lastFlush = firstLog.getFilePointer(); //if write sync is true , prellocate the log file @@ -3796,15 +3798,18 @@ public final class LogToFile implements */ // see if the log file is too big, if it is, switch to the next - // log file - if ((endPosition + LOG_RECORD_OVERHEAD + length) >= - LogCounter.MAX_LOGFILE_SIZE) + // log file. account for an extra INT_LENGTH because switchLogFile() + // writes an extra 0 at the end of the log. in addition, a checksum log record + // may need to be written (see DERBY-2254). + int checksumLogRecordSize = logOut.getChecksumLogRecordSize(); + if ( (endPosition + LOG_RECORD_OVERHEAD + length + INT_LENGTH + checksumLogRecordSize) >= + LogCounter.MAX_LOGFILE_SIZE) { switchLogFile(); // still too big?? Giant log record? - if ((endPosition + LOG_RECORD_OVERHEAD + length) >= - LogCounter.MAX_LOGFILE_SIZE) + if ( (endPosition + LOG_RECORD_OVERHEAD + length + INT_LENGTH + checksumLogRecordSize) >= + LogCounter.MAX_LOGFILE_SIZE) { throw StandardException.newException( SQLState.LOG_EXCEED_MAX_LOG_FILE_SIZE, @@ -3816,7 +3821,7 @@ public final class LogToFile implements } //reserve the space for the checksum log record - endPosition += logOut.reserveSpaceForChecksum(length, logFileNumber,endPosition); + setEndPosition( endPosition + logOut.reserveSpaceForChecksum(length, logFileNumber,endPosition) ); // don't call currentInstant since we are already in a // synchronzied block @@ -3845,7 +3850,7 @@ public final class LogToFile implements } } - endPosition += (length + LOG_RECORD_OVERHEAD); + setEndPosition( endPosition + (length + LOG_RECORD_OVERHEAD) ); } } catch (IOException ioe) @@ -4661,19 +4666,19 @@ public final class LogToFile implements { // reserve the space for the checksum log record // NOTE: bytesToWrite include the log record overhead. - endPosition += + setEndPosition( endPosition + logOut.reserveSpaceForChecksum(((length + LOG_RECORD_OVERHEAD) < bytesToWrite ? length : (bytesToWrite - LOG_RECORD_OVERHEAD)), - logFileNumber,endPosition); + logFileNumber,endPosition) ); instant = currentInstant(); //check if the length of the records to be written is //actually smaller than the number of bytesToWrite if(length + LOG_RECORD_OVERHEAD < bytesToWrite) - endPosition += (length + LOG_RECORD_OVERHEAD); + { setEndPosition( endPosition + (length + LOG_RECORD_OVERHEAD) ); } else - endPosition += bytesToWrite; + { setEndPosition( endPosition + bytesToWrite ); } while(true) // so we can break out without returning out of // sync block... @@ -5296,7 +5301,7 @@ public final class LogToFile implements logEndInstant = scanOfHighestLogFile.getLogRecordEnd(); } - endPosition = LogCounter.getLogFilePosition(logEndInstant); + setEndPosition( LogCounter.getLogFilePosition(logEndInstant) ); // endPosition and logFileNumber now point to the end of the // highest log file. This is where a new log record should be @@ -5734,6 +5739,17 @@ public final class LogToFile implements } } + /** set the endPosition of the log and make sure the new position won't spill off the end of the log */ + private void setEndPosition( long newPosition ) + { + if (SanityManager.DEBUG) + { + SanityManager.ASSERT(newPosition < LogCounter.MAX_LOGFILE_SIZE, + "log file would spill past its legal end if the end were set to = " + newPosition ); + } + + endPosition = newPosition; + }