Repository: activemq Updated Branches: refs/heads/master 9b9e3d367 -> 38d85be47
https://issues.apache.org/jira/browse/AMQ-6590 Fix KahaDB index free page recovery on unclean shutdown so that existing free pages will be tracked and not lost. Project: http://git-wip-us.apache.org/repos/asf/activemq/repo Commit: http://git-wip-us.apache.org/repos/asf/activemq/commit/38d85be4 Tree: http://git-wip-us.apache.org/repos/asf/activemq/tree/38d85be4 Diff: http://git-wip-us.apache.org/repos/asf/activemq/diff/38d85be4 Branch: refs/heads/master Commit: 38d85be476a06fe9a1f60b4f38232d64a6d0398a Parents: 9b9e3d3 Author: Christopher L. Shannon (cshannon) <[email protected]> Authored: Thu Feb 2 07:05:28 2017 -0500 Committer: Christopher L. Shannon (cshannon) <[email protected]> Committed: Thu Feb 2 07:06:11 2017 -0500 ---------------------------------------------------------------------- .../store/kahadb/disk/page/PageFile.java | 18 +++++++----- .../store/kahadb/disk/page/PageFileTest.java | 30 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/activemq/blob/38d85be4/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/page/PageFile.java ---------------------------------------------------------------------- diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/page/PageFile.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/page/PageFile.java index 51b217d..f56539b 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/page/PageFile.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/page/PageFile.java @@ -401,6 +401,8 @@ public class PageFile { recoveryFile = new RecoverableRandomAccessFile(getRecoveryFile(), "rw"); } + boolean needsFreePageRecovery = false; + if (metaData.isCleanShutdown()) { nextTxid.set(metaData.getLastTxId() + 1); if (metaData.getFreePages() > 0) { @@ -409,8 +411,16 @@ public class PageFile { } else { LOG.debug(toString() + ", Recovering page file..."); nextTxid.set(redoRecoveryUpdates()); + needsFreePageRecovery = true; + } + + if (writeFile.length() < PAGE_FILE_HEADER_SIZE) { + writeFile.setLength(PAGE_FILE_HEADER_SIZE); + } + nextFreePageId.set((writeFile.length() - PAGE_FILE_HEADER_SIZE) / pageSize); - // Scan all to find the free pages. + if (needsFreePageRecovery) { + // Scan all to find the free pages after nextFreePageId is set freeList = new SequenceSet(); for (Iterator<Page> i = tx().iterator(true); i.hasNext(); ) { Page page = i.next(); @@ -423,13 +433,7 @@ public class PageFile { metaData.setCleanShutdown(false); storeMetaData(); getFreeFile().delete(); - - if (writeFile.length() < PAGE_FILE_HEADER_SIZE) { - writeFile.setLength(PAGE_FILE_HEADER_SIZE); - } - nextFreePageId.set((writeFile.length() - PAGE_FILE_HEADER_SIZE) / pageSize); startWriter(); - } else { throw new IllegalStateException("Cannot load the page file when it is already loaded."); } http://git-wip-us.apache.org/repos/asf/activemq/blob/38d85be4/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/page/PageFileTest.java ---------------------------------------------------------------------- diff --git a/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/page/PageFileTest.java b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/page/PageFileTest.java index 91f6c40..a39f30c 100644 --- a/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/page/PageFileTest.java +++ b/activemq-kahadb-store/src/test/java/org/apache/activemq/store/kahadb/disk/page/PageFileTest.java @@ -22,9 +22,11 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Field; import java.util.HashSet; import org.apache.activemq.store.kahadb.disk.util.StringMarshaller; +import org.apache.activemq.util.RecoverableRandomAccessFile; import junit.framework.TestCase; @@ -199,4 +201,32 @@ public class PageFileTest extends TestCase { } assertEquals(expected, actual); } + + //Test for AMQ-6590 + public void testFreePageRecoveryUncleanShutdown() throws Exception { + + PageFile pf = new PageFile(new File("target/test-data"), getName()); + pf.delete(); + pf.setEnableRecoveryFile(false); + pf.load(); + + //Allocate 10 free pages + Transaction tx = pf.tx(); + tx.allocate(10); + tx.commit(); + pf.flush(); + + //Load a second instance on the same directory fo the page file which + //simulates an unclean shutdown from the previous run + PageFile pf2 = new PageFile(new File("target/test-data"), getName()); + pf2.setEnableRecoveryFile(false); + pf2.load(); + + long freePages = pf2.getFreePageCount(); + pf.unload(); + pf2.unload(); + + //Make sure that all 10 pages are still tracked + assertEquals(10, freePages); + } }
