mirror of https://github.com/apache/activemq.git
Fix KahaDB index free page recovery on unclean shutdown so that existing
free pages will be tracked and not lost.
(cherry picked from commit 38d85be476
)
This commit is contained in:
parent
58ab9b6c93
commit
6a87e13eb3
|
@ -401,6 +401,8 @@ public class PageFile {
|
||||||
recoveryFile = new RecoverableRandomAccessFile(getRecoveryFile(), "rw");
|
recoveryFile = new RecoverableRandomAccessFile(getRecoveryFile(), "rw");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean needsFreePageRecovery = false;
|
||||||
|
|
||||||
if (metaData.isCleanShutdown()) {
|
if (metaData.isCleanShutdown()) {
|
||||||
nextTxid.set(metaData.getLastTxId() + 1);
|
nextTxid.set(metaData.getLastTxId() + 1);
|
||||||
if (metaData.getFreePages() > 0) {
|
if (metaData.getFreePages() > 0) {
|
||||||
|
@ -409,8 +411,16 @@ public class PageFile {
|
||||||
} else {
|
} else {
|
||||||
LOG.debug(toString() + ", Recovering page file...");
|
LOG.debug(toString() + ", Recovering page file...");
|
||||||
nextTxid.set(redoRecoveryUpdates());
|
nextTxid.set(redoRecoveryUpdates());
|
||||||
|
needsFreePageRecovery = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Scan all to find the free pages.
|
if (writeFile.length() < PAGE_FILE_HEADER_SIZE) {
|
||||||
|
writeFile.setLength(PAGE_FILE_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
nextFreePageId.set((writeFile.length() - PAGE_FILE_HEADER_SIZE) / pageSize);
|
||||||
|
|
||||||
|
if (needsFreePageRecovery) {
|
||||||
|
// Scan all to find the free pages after nextFreePageId is set
|
||||||
freeList = new SequenceSet();
|
freeList = new SequenceSet();
|
||||||
for (Iterator<Page> i = tx().iterator(true); i.hasNext(); ) {
|
for (Iterator<Page> i = tx().iterator(true); i.hasNext(); ) {
|
||||||
Page page = i.next();
|
Page page = i.next();
|
||||||
|
@ -423,13 +433,7 @@ public class PageFile {
|
||||||
metaData.setCleanShutdown(false);
|
metaData.setCleanShutdown(false);
|
||||||
storeMetaData();
|
storeMetaData();
|
||||||
getFreeFile().delete();
|
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();
|
startWriter();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Cannot load the page file when it is already loaded.");
|
throw new IllegalStateException("Cannot load the page file when it is already loaded.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,11 @@ import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import org.apache.activemq.store.kahadb.disk.util.StringMarshaller;
|
import org.apache.activemq.store.kahadb.disk.util.StringMarshaller;
|
||||||
|
import org.apache.activemq.util.RecoverableRandomAccessFile;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
@ -199,4 +201,32 @@ public class PageFileTest extends TestCase {
|
||||||
}
|
}
|
||||||
assertEquals(expected, actual);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue