From 7bd23681d15940407c9d53666e091fcaaf9666b5 Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Thu, 18 Nov 2010 04:16:05 +0000 Subject: [PATCH] ignore usagemap inconsistencies in certain situations git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@499 f203690c-595d-4dc9-a70b-905162fa7fd2 --- src/changes/changes.xml | 3 + .../jackcess/PageChannel.java | 4 +- .../jackcess/UsageMap.java | 63 +++++++++++++++---- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1ff8609..d6b1461 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -27,6 +27,9 @@ Add support for custom column value matching when finding rows using a Cursor. + + Ignore usagemap inconsistencies in certain situations. + diff --git a/src/java/com/healthmarketscience/jackcess/PageChannel.java b/src/java/com/healthmarketscience/jackcess/PageChannel.java index 7d79d80..518007a 100644 --- a/src/java/com/healthmarketscience/jackcess/PageChannel.java +++ b/src/java/com/healthmarketscience/jackcess/PageChannel.java @@ -258,7 +258,9 @@ public class PageChannel implements Channel, Flushable { int pageNumber = getNextPageNumber(size); _channel.write(_codecHandler.encodePage(page, pageNumber, pageOffset), offset); - _globalUsageMap.removePageNumber(pageNumber); //force is done here + // note, we "force" page removal because we know that this is an unused + // page (since we just added it to the file) + _globalUsageMap.removePageNumber(pageNumber, true); return pageNumber; } diff --git a/src/java/com/healthmarketscience/jackcess/UsageMap.java b/src/java/com/healthmarketscience/jackcess/UsageMap.java index 5e6ec1e..d60141e 100644 --- a/src/java/com/healthmarketscience/jackcess/UsageMap.java +++ b/src/java/com/healthmarketscience/jackcess/UsageMap.java @@ -301,20 +301,29 @@ public class UsageMap */ public void addPageNumber(int pageNumber) throws IOException { ++_modCount; - _handler.addOrRemovePageNumber(pageNumber, true); + _handler.addOrRemovePageNumber(pageNumber, true, false); } /** * Remove a page number from this usage map */ public void removePageNumber(int pageNumber) throws IOException { + removePageNumber(pageNumber, false); + } + + /** + * Remove a page number from this usage map + */ + protected void removePageNumber(int pageNumber, boolean force) + throws IOException + { ++_modCount; - _handler.addOrRemovePageNumber(pageNumber, false); + _handler.addOrRemovePageNumber(pageNumber, false, force); } protected void updateMap(int absolutePageNumber, int bufferRelativePageNumber, - ByteBuffer buffer, boolean add) + ByteBuffer buffer, boolean add, boolean force) throws IOException { //Find the byte to which to apply the bitmask and create the bitmask @@ -325,7 +334,7 @@ public class UsageMap // check current value for this page number int pageNumberOffset = pageNumberToBitIndex(absolutePageNumber); boolean isOn = _pageNumbers.get(pageNumberOffset); - if(isOn == add) { + if((isOn == add) && !force) { throw new IOException("Page number " + absolutePageNumber + " already " + ((add) ? "added to" : "removed from") + " usage map, expected range " + @@ -390,17 +399,41 @@ public class UsageMap StringBuilder builder = new StringBuilder( "(" + _handler.getClass().getSimpleName() + ") page numbers (range " + _startPage + " " + _endPage + "): ["); + PageCursor pCursor = cursor(); + int curRangeStart = Integer.MIN_VALUE; + int prevPage = Integer.MIN_VALUE; while(true) { int nextPage = pCursor.getNextPage(); if(nextPage < 0) { break; } - builder.append(nextPage).append(", "); + + if(nextPage != (prevPage + 1)) { + if(prevPage >= 0) { + rangeToString(builder, curRangeStart, prevPage); + } + curRangeStart = nextPage; + } + prevPage = nextPage; + } + if(prevPage >= 0) { + rangeToString(builder, curRangeStart, prevPage); } + builder.append("]"); return builder.toString(); } + + private static void rangeToString(StringBuilder builder, int rangeStart, + int rangeEnd) + { + builder.append(rangeStart); + if(rangeEnd > rangeStart) { + builder.append("-").append(rangeEnd); + } + builder.append(", "); + } private abstract class Handler { @@ -415,8 +448,10 @@ public class UsageMap /** * @param pageNumber Page number to add or remove from this map * @param add True to add it, false to remove it + * @param force true to force add/remove and ignore certain inconsistencies */ - public abstract void addOrRemovePageNumber(int pageNumber, boolean add) + public abstract void addOrRemovePageNumber(int pageNumber, boolean add, + boolean force) throws IOException; } @@ -471,14 +506,16 @@ public class UsageMap } @Override - public void addOrRemovePageNumber(int pageNumber, boolean add) + public void addOrRemovePageNumber(int pageNumber, boolean add, + boolean force) throws IOException { if(isPageWithinRange(pageNumber)) { // easy enough, just update the inline data int bufferRelativePageNumber = pageNumberToBitIndex(pageNumber); - updateMap(pageNumber, bufferRelativePageNumber, getTableBuffer(), add); + updateMap(pageNumber, bufferRelativePageNumber, getTableBuffer(), add, + force); // Write the updated map back to disk writeTable(); @@ -535,7 +572,7 @@ public class UsageMap } - } else { + } else if(!force) { // this should not happen, we are removing a page which is not in // the map @@ -671,10 +708,14 @@ public class UsageMap } @Override - public void addOrRemovePageNumber(int pageNumber, boolean add) + public void addOrRemovePageNumber(int pageNumber, boolean add, + boolean force) throws IOException { if(!isPageWithinRange(pageNumber)) { + if(force) { + return; + } throw new IOException("Page number " + pageNumber + " is out of supported range"); } @@ -691,7 +732,7 @@ public class UsageMap } updateMap(pageNumber, (pageNumber - (getMaxPagesPerUsagePage() * pageIndex)), - mapPageBuffer, add); + mapPageBuffer, add, force); getPageChannel().writePage(mapPageBuffer, mapPageNum); } -- 2.39.5