- Fix FLB full check

- Cache FLB
- FLB logging, cleanups, checks
This commit is contained in:
zzz
2011-03-28 14:27:19 +00:00
parent 9fcb20a7bd
commit 33780ef359
2 changed files with 53 additions and 14 deletions

View File

@@ -71,7 +71,7 @@ public class BlockFile {
public static final long OFFSET_MOUNTED = 20; public static final long OFFSET_MOUNTED = 20;
public static final Log log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class); public static final Log log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class);
public RandomAccessInterface file; public final RandomAccessInterface file;
private static final int MAJOR = 0x01; private static final int MAJOR = 0x01;
private static final int MINOR = 0x01; private static final int MINOR = 0x01;
@@ -84,13 +84,16 @@ public class BlockFile {
/** 2**32 pages of 1024 bytes each, more or less */ /** 2**32 pages of 1024 bytes each, more or less */
private static final long MAX_LEN = (2l << (32 + 10)) - 1; private static final long MAX_LEN = (2l << (32 + 10)) - 1;
/** new BlockFile length, containing a superblock page and a metaindex page. */
private long fileLen = PAGESIZE * 2; private long fileLen = PAGESIZE * 2;
private int freeListStart = 0; private int freeListStart = 0;
private int mounted = 0; private int mounted = 0;
public int spanSize = 16; public int spanSize = 16;
private BSkipList metaIndex = null; private BSkipList metaIndex;
private HashMap openIndices = new HashMap(); /** cached list of free pages, only valid if freListStart > 0 */
private FreeListBlock flb;
private final HashMap openIndices = new HashMap();
private void mount() throws IOException { private void mount() throws IOException {
file.seek(BlockFile.OFFSET_MOUNTED); file.seek(BlockFile.OFFSET_MOUNTED);
@@ -268,7 +271,7 @@ public class BlockFile {
if(init) { if(init) {
file.setLength(fileLen); file.setLength(fileLen);
writeSuperBlock(); writeSuperBlock();
BSkipList.init(this, 2, spanSize); BSkipList.init(this, METAINDEX_PAGE, spanSize);
} }
readSuperBlock(); readSuperBlock();
@@ -304,13 +307,20 @@ public class BlockFile {
public int allocPage() throws IOException { public int allocPage() throws IOException {
if(freeListStart != 0) { if(freeListStart != 0) {
try { try {
FreeListBlock flb = new FreeListBlock(file, freeListStart); if (flb == null)
flb = new FreeListBlock(file, freeListStart);
if(!flb.isEmpty()) { if(!flb.isEmpty()) {
if (log.shouldLog(Log.INFO))
log.info("Alloc from " + flb);
return flb.takePage(); return flb.takePage();
} else { } else {
if (log.shouldLog(Log.INFO))
log.info("Alloc returning empty " + flb);
freeListStart = flb.getNextPage(); freeListStart = flb.getNextPage();
writeSuperBlock(); writeSuperBlock();
return flb.page; int rv = flb.page;
flb = null;
return rv;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
log.error("Discarding corrupt free list block page " + freeListStart, ioe); log.error("Discarding corrupt free list block page " + freeListStart, ioe);
@@ -330,8 +340,8 @@ public class BlockFile {
* Does not throw exceptions; logs on failure. * Does not throw exceptions; logs on failure.
*/ */
public void freePage(int page) { public void freePage(int page) {
if (page < METAINDEX_PAGE) { if (page <= METAINDEX_PAGE) {
log.error("Negative page or superblock free attempt: " + page); log.error("Bad page free attempt: " + page);
return; return;
} }
try { try {
@@ -339,29 +349,43 @@ public class BlockFile {
freeListStart = page; freeListStart = page;
FreeListBlock.initPage(file, page); FreeListBlock.initPage(file, page);
writeSuperBlock(); writeSuperBlock();
if (log.shouldLog(Log.INFO))
log.info("Freed page " + page + " as new FLB");
return; return;
} }
try { try {
FreeListBlock flb = new FreeListBlock(file, freeListStart); if (flb == null)
flb = new FreeListBlock(file, freeListStart);
if(flb.isFull()) { if(flb.isFull()) {
// Make the free page a new FLB
if (log.shouldLog(Log.INFO))
log.info("Full: " + flb);
FreeListBlock.initPage(file, page); FreeListBlock.initPage(file, page);
if(flb.getNextPage() == 0) { if(flb.getNextPage() == 0) {
// Put it at the tail.
// Next free will make a new FLB at the head,
// so we have one more FLB than we need.
flb.setNextPage(page); flb.setNextPage(page);
return;
} else { } else {
// Put it at the head
flb = new FreeListBlock(file, page); flb = new FreeListBlock(file, page);
flb.setNextPage(freeListStart); flb.setNextPage(freeListStart);
freeListStart = page; freeListStart = page;
writeSuperBlock(); writeSuperBlock();
return;
} }
if (log.shouldLog(Log.INFO))
log.info("Freed page " + page + " to full " + flb);
return;
} }
flb.addPage(page); flb.addPage(page);
if (log.shouldLog(Log.INFO))
log.info("Freed page " + page + " to " + flb);
} catch (IOException ioe) { } catch (IOException ioe) {
log.error("Discarding corrupt free list block page " + freeListStart, ioe); log.error("Discarding corrupt free list block page " + freeListStart, ioe);
freeListStart = page; freeListStart = page;
FreeListBlock.initPage(file, page); FreeListBlock.initPage(file, page);
writeSuperBlock(); writeSuperBlock();
flb = null;
} }
} catch (IOException ioe) { } catch (IOException ioe) {
log.error("Error freeing page: " + page, ioe); log.error("Error freeing page: " + page, ioe);

View File

@@ -69,8 +69,16 @@ class FreeListBlock {
throw new IOException("Bad freelist size " + len); throw new IOException("Bad freelist size " + len);
branches = new int[MAX_SIZE]; branches = new int[MAX_SIZE];
if(len > 0) { if(len > 0) {
int good = 0;
for(int i=0;i<len;i++) { for(int i=0;i<len;i++) {
branches[i] = file.readUnsignedInt(); int fpg = file.readInt();
if (fpg > BlockFile.METAINDEX_PAGE)
branches[good++] = fpg;
}
if (good != len) {
BlockFile.log.error((len - good) + " bad pages in " + this);
len = good;
writeBlock();
} }
} }
} }
@@ -123,7 +131,7 @@ class FreeListBlock {
} }
public boolean isFull() { public boolean isFull() {
return len < MAX_SIZE; return len >= MAX_SIZE;
} }
/** /**
@@ -152,6 +160,9 @@ class FreeListBlock {
len--; len--;
writeLen(); writeLen();
int rv = branches[len]; int rv = branches[len];
if (rv <= BlockFile.METAINDEX_PAGE)
// shouldn't happen
throw new IOException("Bad free page " + rv);
long magic = getMagic(rv); long magic = getMagic(rv);
if (magic != MAGIC_FREE) if (magic != MAGIC_FREE)
// TODO keep trying until empty // TODO keep trying until empty
@@ -176,5 +187,9 @@ class FreeListBlock {
file.writeInt(0); file.writeInt(0);
file.writeInt(0); file.writeInt(0);
} }
}
@Override
public String toString() {
return "FLB with " + len + " / " + MAX_SIZE + " page " + page + " next page " + nextPage;
}
}