/** * Something is wrong with this file. If there is no data in this file (the header is <= the file * header size) then move this last file aside and search the next "last" file. If the last file * does have data in it, return null and throw an exception back to the application, since we're * not sure what to do now. * * @param cause is a DatabaseException or ChecksumException. */ private Long attemptToMoveBadFile(Exception cause) throws IOException, ChecksumException, DatabaseException { String fileName = fileManager.getFullFileNames(window.currentFileNum())[0]; File problemFile = new File(fileName); if (problemFile.length() <= FileManager.firstLogEntryOffset()) { fileManager.clear(); // close all existing files /* Move this file aside. */ Long lastNum = fileManager.getFollowingFileNum(window.currentFileNum(), false); if (!fileManager.renameFile(window.currentFileNum(), FileManager.BAD_SUFFIX)) { throw EnvironmentFailureException.unexpectedState( "Could not rename file: 0x" + Long.toHexString(window.currentFileNum())); } return lastNum; } /* There's data in this file, throw up to the app. */ if (cause instanceof DatabaseException) { throw (DatabaseException) cause; } if (cause instanceof ChecksumException) { throw (ChecksumException) cause; } throw EnvironmentFailureException.unexpectedException(cause); }
/** Override so that we always start at the last file. */ protected void initStartingPosition(long endOfFileLsn, Long singleFileNum) throws IOException, DatabaseException { eof = false; /* * Start at what seems like the last file. If it doesn't exist, we're * done. */ Long lastNum = ((singleFileNum != null) && (singleFileNum.longValue() >= 0)) ? singleFileNum : fileManager.getLastFileNum(); FileHandle fileHandle = null; readBufferFileEnd = 0; long fileLen = 0; while ((fileHandle == null) && !eof) { if (lastNum == null) { eof = true; } else { try { readBufferFileNum = lastNum.longValue(); fileHandle = fileManager.getFileHandle(readBufferFileNum); /* * Check the size of this file. If it opened successfully * but only held a header or is 0 length, backup to the * next "last" file unless this is the only file in the * log. Note that an incomplete header will end up throwing * a checksum exception, but a 0 length file will open * successfully in read only mode. */ fileLen = fileHandle.getFile().length(); if (fileLen <= FileManager.firstLogEntryOffset()) { lastNum = fileManager.getFollowingFileNum(lastNum.longValue(), false); if (lastNum != null) { fileHandle.release(); fileHandle = null; } } } catch (DatabaseException e) { lastNum = attemptToMoveBadFile(e); fileHandle = null; } finally { if (fileHandle != null) { fileHandle.release(); } } } } nextEntryOffset = 0; }
/** * Something is wrong with this file. If there is no data in this file (the header is <= the file * header size) then move this last file aside and search the next "last" file. If the last file * does have data in it, throw an exception back to the application, since we're not sure what to * do now. */ private Long attemptToMoveBadFile(DatabaseException origException) throws DatabaseException, IOException { String fileName = fileManager.getFullFileNames(readBufferFileNum)[0]; File problemFile = new File(fileName); Long lastNum = null; if (problemFile.length() <= FileManager.firstLogEntryOffset()) { fileManager.clear(); // close all existing files /* Move this file aside. */ lastNum = fileManager.getFollowingFileNum(readBufferFileNum, false); fileManager.renameFile(readBufferFileNum, FileManager.BAD_SUFFIX); } else { /* There's data in this file, throw up to the app. */ throw origException; } return lastNum; }
public void testTruncatedHeader() throws IOException, DatabaseException { /* Create a log file */ FileManagerTestUtils.createLogFile(fileManager, envImpl, FILE_SIZE); /* Truncate the header */ RandomAccessFile file0 = new RandomAccessFile( fileManager.getFullFileName(0, FileManager.JE_SUFFIX), FileManager.FileMode.READWRITE_MODE.getModeValue()); file0.getChannel().truncate(FileManager.firstLogEntryOffset() / 2); file0.close(); try { fileManager.getFileHandle(0); fail("Should see assertion"); } catch (DatabaseException e) { } }
/** Test initializing the last position in the logs. */ public void testSetLastPosition() throws DatabaseException { /* * Pretend that the last file is file 79. */ fileManager.setLastPosition( // next available LSN DbLsn.makeLsn(79L, 88L), DbLsn.makeLsn(79L, 77), 66L); /* Put an entry down, should fit within file 79. */ fileManager.bumpLsn(11L); assertEquals(DbLsn.makeLsn(79L, 88L), fileManager.getLastUsedLsn()); assertEquals(77L, fileManager.getPrevEntryOffset()); /* Put another entry in, should go to the next file. */ fileManager.bumpLsn(22L); assertEquals( DbLsn.makeLsn(80L, FileManager.firstLogEntryOffset()), fileManager.getLastUsedLsn()); assertEquals(0, fileManager.getPrevEntryOffset()); }
/** See if we can catch a file with an invalid header. */ public void testBadHeader() throws IOException, DatabaseException { /* First try a bad environment r/w. */ try { FileManager test = new FileManager(envImpl, new File("xxyy"), true); fail("expect creation of " + test + "to fail."); } catch (LogException e) { /* should throw */ } /* Next try a bad environment r/o. */ try { FileManager test = new FileManager(envImpl, new File("xxyy"), false); fail("expect creation of " + test + "to fail."); } catch (DatabaseException e) { /* should throw */ } /* Now create a file, but mess up the header. */ FileManagerTestUtils.createLogFile(fileManager, envImpl, FILE_SIZE); byte[] badData = new byte[] {1, 1}; int headerSize = FileManager.firstLogEntryOffset(); RandomAccessFile file0 = new RandomAccessFile( fileManager.getFullFileName(0, FileManager.JE_SUFFIX), FileManager.FileMode.READWRITE_MODE.getModeValue()); file0.write(badData); file0.close(); fileManager.clear(); try { FileHandle file0Handle = fileManager.getFileHandle(0L); fail("expect to catch a checksum error"); } catch (DbChecksumException e) { } }
/** Initialize starting position to the last file with a complete header with a valid checksum. */ private void startAtLastGoodFile(Long singleFileNum) throws ChecksumException { eof = false; window.initAtFileStart(DbLsn.makeLsn(0, 0)); /* * Start at what seems like the last file. If it doesn't exist, we're * done. */ Long lastNum = ((singleFileNum != null) && (singleFileNum.longValue() >= 0)) ? singleFileNum : fileManager.getLastFileNum(); FileHandle fileHandle = null; long fileLen = 0; while ((fileHandle == null) && !eof) { if (lastNum == null) { eof = true; } else { try { try { window.initAtFileStart(DbLsn.makeLsn(lastNum, 0)); fileHandle = fileManager.getFileHandle(lastNum); /* * Check the size of this file. If it opened * successfully but only held a header or is 0 length, * backup to the next "last" file unless this is the * only file in the log. Note that an incomplete header * will end up throwing a checksum exception, but a 0 * length file will open successfully in read only * mode. */ fileLen = fileHandle.getFile().length(); if (fileLen <= FileManager.firstLogEntryOffset()) { lastNum = fileManager.getFollowingFileNum(lastNum, false); if (lastNum != null) { fileHandle.release(); fileHandle = null; } } } catch (DatabaseException e) { lastNum = attemptToMoveBadFile(e); fileHandle = null; } catch (ChecksumException e) { lastNum = attemptToMoveBadFile(e); fileHandle = null; } finally { if (fileHandle != null) { fileHandle.release(); } } } catch (IOException e) { throw new EnvironmentFailureException(envImpl, EnvironmentFailureReason.LOG_READ, e); } } } nextEntryOffset = 0; }
/** Test LSN administration. */ public void testLsnBumping() throws Exception { /* We are adding these entries: +----+------+---------+--------+ file 0: |hdr | 30 | 50 |empty | +----+------+---------+--------+ 0 hdr hdr+30 hdr+80 99 +----+--------+-------+-------+-----+-------+ file 1: |hdr | 40 | 20 | 10 | 5 | empty | +----+--------+-------+-------+-----+-------+ 0 hdr hdr+40 hdr+60 hdr+70 hdr+75 +-----+-----+--------+ file 2: | hdr | 75 | empty | +-----+-----+--------+ 0 hdr hdr+75 +-----+-------------------------------+ file 3: | hdr | 125 | +-----+-------------------------------+ 0 hdr +-----+-----+------+-----+--------------+ file 4: | hdr | 10 | 20 | 30 | empty +-----+-----+------+-----+--------------+ 0 hdr hdr+10 hdr+30 */ try { /* Should start out at LSN 0. */ /* "add" some entries to the log. */ long hdrSize = FileManager.firstLogEntryOffset(); fileManager.bumpLsn(30L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(0, hdrSize), fileManager.getLastUsedLsn()); /* prev entry. */ assertEquals(0, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(50L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(0, (hdrSize + 30)), fileManager.getLastUsedLsn()); assertEquals(hdrSize, fileManager.getPrevEntryOffset()); /* bump over to a file 1. */ fileManager.bumpLsn(40L); /* item placed here. */ assertEquals(DbLsn.makeLsn(1, hdrSize), fileManager.getLastUsedLsn()); assertEquals(0, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(20L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(1, (hdrSize + 40)), fileManager.getLastUsedLsn()); assertEquals(hdrSize, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(10L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(1, (hdrSize + 60)), fileManager.getLastUsedLsn()); assertEquals(hdrSize + 40, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(5L); /* item placed here. */ assertEquals(DbLsn.makeLsn(1, (hdrSize + 70)), fileManager.getLastUsedLsn()); assertEquals(hdrSize + 60, fileManager.getPrevEntryOffset()); /* bump over to file 2. */ fileManager.bumpLsn(75L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(2, hdrSize), fileManager.getLastUsedLsn()); assertEquals(0, fileManager.getPrevEntryOffset()); /* Ask for something bigger than a file: bump over to file 3. */ fileManager.bumpLsn(125L); /* item placed here. */ assertEquals(DbLsn.makeLsn(3, hdrSize), fileManager.getLastUsedLsn()); assertEquals(0, fileManager.getPrevEntryOffset()); /* bump over to file 4. */ fileManager.bumpLsn(10L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(4, hdrSize), fileManager.getLastUsedLsn()); assertEquals(0, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(20L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(4, (hdrSize + 10)), fileManager.getLastUsedLsn()); assertEquals(hdrSize, fileManager.getPrevEntryOffset()); fileManager.bumpLsn(30L); /* Item placed here. */ assertEquals(DbLsn.makeLsn(4, (hdrSize + 30)), fileManager.getLastUsedLsn()); assertEquals((hdrSize + 10), fileManager.getPrevEntryOffset()); } catch (Exception e) { e.printStackTrace(); throw e; } }