From 4bf77267a5871e0da49c07e7e750e9207a9daddd Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Tue, 8 Apr 2008 01:05:15 +0000 Subject: [PATCH] more minor refactoring git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@317 f203690c-595d-4dc9-a70b-905162fa7fd2 --- .../healthmarketscience/jackcess/Index.java | 8 +- .../jackcess/IndexPageCache.java | 141 +++++++++++++----- 2 files changed, 108 insertions(+), 41 deletions(-) diff --git a/src/java/com/healthmarketscience/jackcess/Index.java b/src/java/com/healthmarketscience/jackcess/Index.java index 4dc822f..cb8867f 100644 --- a/src/java/com/healthmarketscience/jackcess/Index.java +++ b/src/java/com/healthmarketscience/jackcess/Index.java @@ -586,7 +586,7 @@ public abstract class Index implements Comparable { DataPage nextDataPage = null; while(nextPageNumber != INVALID_INDEX_PAGE_NUMBER) { DataPage dp = getDataPage(nextPageNumber); - if(!dp.getEntries().isEmpty()) { + if(!dp.isEmpty()) { nextDataPage = dp; break; } @@ -615,7 +615,7 @@ public abstract class Index implements Comparable { DataPage prevDataPage = null; while(prevPageNumber != INVALID_INDEX_PAGE_NUMBER) { DataPage dp = getDataPage(prevPageNumber); - if(!dp.getEntries().isEmpty()) { + if(!dp.isEmpty()) { prevDataPage = dp; break; } @@ -2199,6 +2199,10 @@ public abstract class Index implements Comparable { throws IOException; public abstract void removeEntry(int idx) throws IOException; + + public final boolean isEmpty() { + return getEntries().isEmpty(); + } public final int getCompressedEntrySize() { // when written to the index page, the entryPrefix bytes will only be diff --git a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java index da4acb7..1e94f86 100644 --- a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java +++ b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java @@ -34,8 +34,10 @@ import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; + import org.apache.commons.lang.ObjectUtils; import static com.healthmarketscience.jackcess.Index.*; @@ -86,26 +88,56 @@ public class IndexPageCache public void write() throws IOException { + // first discard any empty pages + handleEmptyPages(); + // next, handle any necessary page splitting preparePagesForWriting(); + // finally, write all the modified pages (which are not being deleted) writeDataPages(); } - private void preparePagesForWriting() - throws IOException + private void handleEmptyPages() throws IOException { - // FIXME, writeme + for(Iterator iter = _modifiedPages.iterator(); + iter.hasNext(); ) { + CacheDataPage cacheDataPage = iter.next(); + if(cacheDataPage.isEmpty()) { + if(!cacheDataPage._main.isRoot()) { + deleteDataPage(cacheDataPage); + } else { + writeDataPage(cacheDataPage); + } + iter.remove(); + } + } + } + + private void preparePagesForWriting() throws IOException + { + boolean splitPages = false; + int maxPageEntrySize = getIndex().getMaxPageEntrySize(); + do { + splitPages = false; + + for(CacheDataPage cacheDataPage : _modifiedPages) { + if(cacheDataPage.getCompressedEntrySize() > maxPageEntrySize) { + // need to split this page + splitPages = true; + splitDataPage(cacheDataPage); + } + } + + } while(splitPages); } - private void writeDataPages() - throws IOException + private void writeDataPages() throws IOException { for(CacheDataPage cacheDataPage : _modifiedPages) { - if(!cacheDataPage.getEntries().isEmpty() || - cacheDataPage._main.isRoot()) { - writeDataPage(cacheDataPage); - } else { - deleteDataPage(cacheDataPage); + if(cacheDataPage.isEmpty()) { + throw new IllegalStateException("Unexpected empty page " + + cacheDataPage); } + writeDataPage(cacheDataPage); } _modifiedPages.clear(); } @@ -219,12 +251,12 @@ public class IndexPageCache setModified(cacheDataPage); - boolean updateFirst = false; + boolean updateFirst = (entryIdx == 0); boolean updateLast = false; + boolean mayUpdatePrefix = true; switch(upType) { case ADD: { - updateFirst = (entryIdx == 0); updateLast = (entryIdx == dpExtra._entries.size()); dpExtra._entries.add(entryIdx, newEntry); @@ -232,7 +264,6 @@ public class IndexPageCache break; } case REPLACE: { - updateFirst = (entryIdx == 0); updateLast = (entryIdx == (dpExtra._entries.size() - 1)); Entry oldEntry = dpExtra._entries.set(entryIdx, newEntry); @@ -240,18 +271,20 @@ public class IndexPageCache break; } case REMOVE: { - updateFirst = (entryIdx == 0); updateLast = (entryIdx == (dpExtra._entries.size() - 1)); Entry oldEntry = dpExtra._entries.remove(entryIdx); dpExtra._totalEntrySize -= oldEntry.size(); + // note, we don't need to futz with the _entryPrefix on removal because + // the prefix is always still valid after removal + mayUpdatePrefix = false; break; } default: throw new RuntimeException("unknown update type " + upType); } - if(dpExtra._entries.isEmpty()) { + if(cacheDataPage.isEmpty()) { // this page is dead removeDataPage(cacheDataPage); } else { @@ -261,9 +294,7 @@ public class IndexPageCache if(updateLast) { dpMain._lastEntry = dpExtra.getLastEntry(); } - // note, we don't need to futz with the _entryPrefix on removal because - // the prefix is always still valid after removal - if((upType != UpdateType.REMOVE) && (updateFirst || updateLast)) { + if(mayUpdatePrefix && (updateFirst || updateLast)) { // update the prefix dpExtra._entryPrefix = findNewPrefix(dpExtra._entryPrefix, newEntry); } @@ -306,20 +337,12 @@ public class IndexPageCache setModified(parentDataPage); DataPageMain parentMain = parentDataPage._main; - DataPageExtra parentExtra = parentDataPage._extra; if(childMain.isTail()) { parentMain._childTailPageNumber = INVALID_INDEX_PAGE_NUMBER; } else { - Entry oldParentEntry = childMain._firstEntry.asNodeEntry( - childMain._pageNumber); - int idx = parentExtra.findEntry(oldParentEntry); - if(idx < 0) { - throw new IllegalStateException( - "Could not find child entry in parent; child " + childDataPage + - "; parent " + parentDataPage); - } - removeEntry(parentDataPage, idx); + updateParentEntry(parentDataPage, childDataPage, + childMain._firstEntry, null, UpdateType.REMOVE); } } @@ -354,31 +377,65 @@ public class IndexPageCache dpMain._firstEntry = dpExtra.getFirstEntry(); DataPageMain parentMain = dpMain.getParentPage(); if(parentMain != null) { - Entry oldParentEntry = oldEntry.asNodeEntry(dpMain._pageNumber); - Entry newParentEntry = - dpMain._firstEntry.asNodeEntry(dpMain._pageNumber); updateParentEntry(new CacheDataPage(parentMain), - oldParentEntry, newParentEntry); + cacheDataPage, + oldEntry, dpMain._firstEntry, + UpdateType.REPLACE); } } private void updateParentEntry(CacheDataPage parentDataPage, - Entry oldEntry, Entry newEntry) + CacheDataPage childDataPage, + Entry oldEntry, Entry newEntry, + UpdateType upType) throws IOException { + DataPageMain childMain = childDataPage._main; DataPageExtra parentExtra = parentDataPage._extra; - setModified(parentDataPage); + if(oldEntry != null) { + oldEntry = oldEntry.asNodeEntry(childMain._pageNumber); + } + if(newEntry != null) { + newEntry = newEntry.asNodeEntry(childMain._pageNumber); + } + + boolean expectFound = true; + int idx = 0; + + switch(upType) { + case ADD: + expectFound = false; + idx = parentExtra.findEntry(newEntry); + break; - int idx = parentExtra.findEntry(oldEntry); + case REPLACE: + case REMOVE: + idx = parentExtra.findEntry(oldEntry); + break; + + default: + throw new RuntimeException("unknown update type " + upType); + } + if(idx < 0) { - throw new IllegalStateException( - "Could not find child entry in parent; childEntry " + oldEntry + - "; parent " + parentDataPage); + if(expectFound) { + throw new IllegalStateException( + "Could not find child entry in parent; childEntry " + oldEntry + + "; parent " + parentDataPage); + } + idx = missingIndexToInsertionPoint(idx); + } else { + if(!expectFound) { + throw new IllegalStateException( + "Unexpectedly found child entry in parent; childEntry " + + newEntry + "; parent " + parentDataPage); + } } - replaceEntry(parentDataPage, idx, newEntry); + updateEntry(parentDataPage, idx, newEntry, upType); } + private void validateEntryForPage(DataPageMain dataPage, Entry entry) { if(dataPage._leaf != entry.isLeafEntry()) { throw new IllegalStateException( @@ -386,6 +443,12 @@ public class IndexPageCache dataPage._leaf + ", entryLeaf " + entry.isLeafEntry()); } } + + private void splitDataPage(CacheDataPage cacheDataPage) + throws IOException + { + // FIXME, writeme + } public CacheDataPage findCacheDataPage(Entry e) throws IOException -- 2.39.5