From 15465c0260125b61b7888e67a1d38d583d357893 Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Sat, 19 Apr 2008 02:44:56 +0000 Subject: [PATCH] fix tail demotion git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@336 f203690c-595d-4dc9-a70b-905162fa7fd2 --- .../jackcess/IndexPageCache.java | 45 +++++++++++++------ .../jackcess/BigIndexTest.java | 22 ++++++++- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java index 0c0d890..2fc8617 100644 --- a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java +++ b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java @@ -101,7 +101,7 @@ public class IndexPageCache for(Iterator iter = _modifiedPages.iterator(); iter.hasNext(); ) { CacheDataPage cacheDataPage = iter.next(); - if(cacheDataPage.isEmpty()) { + if(cacheDataPage._extra._entryView.isEmpty()) { if(!cacheDataPage._main.isRoot()) { deleteDataPage(cacheDataPage); } else { @@ -162,7 +162,7 @@ public class IndexPageCache private void writeDataPages() throws IOException { for(CacheDataPage cacheDataPage : _modifiedPages) { - if(cacheDataPage.isEmpty()) { + if(cacheDataPage._extra._entryView.isEmpty()) { throw new IllegalStateException("Unexpected empty page " + cacheDataPage); } @@ -705,10 +705,16 @@ public class IndexPageCache // there's only one entry on the page, and it's the tail. make it a // normal entry DataPageMain dpMain = cacheDataPage._main; + DataPageExtra dpExtra = cacheDataPage._extra; DataPageMain tailMain = dpMain.getChildTailPage(); CacheDataPage tailDataPage = new CacheDataPage(tailMain); - removeParentEntry(tailDataPage); + + // note, we can't just call removeParentEntry here cause that will attempt + // to delete the parent page (since it would be empty), so we have to + // remove the parent entry manually + updateParentTail(cacheDataPage, tailDataPage, UpdateType.REMOVE); + dpExtra._entryView.clear(); tailMain.setParentPage(dpMain._pageNumber, false); @@ -834,10 +840,13 @@ public class IndexPageCache int childTailPageNumber = dpMain._childTailPageNumber; if(dpMain._leaf) { if(childTailPageNumber != INVALID_INDEX_PAGE_NUMBER) { - throw new IllegalStateException("Leaf page has tail"); + throw new IllegalStateException("Leaf page has tail " + dpMain); } return; } + if((dpExtra._entryView.size() == 1) && dpMain.hasChildTail()) { + throw new IllegalStateException("Single child is tail " + dpMain); + } for(Entry e : dpExtra._entryView) { validateEntryForPage(dpMain, e); Integer subPageNumber = e.getSubPageNumber(); @@ -1194,9 +1203,13 @@ public class IndexPageCache _extra = extra; } + private List getEntries() { + return _extra._entries; + } + @Override public int size() { - int size = _extra._entries.size(); + int size = getEntries().size(); if(hasChildTail()) { ++size; } @@ -1207,14 +1220,14 @@ public class IndexPageCache public Entry get(int idx) { return (isCurrentChildTailIndex(idx) ? _childTailEntry : - _extra._entries.get(idx)); + getEntries().get(idx)); } @Override public Entry set(int idx, Entry newEntry) { return (isCurrentChildTailIndex(idx) ? setChildTailEntry(newEntry) : - _extra._entries.set(idx, newEntry)); + getEntries().set(idx, newEntry)); } @Override @@ -1222,7 +1235,7 @@ public class IndexPageCache if(isNewChildTailIndex(idx)) { setChildTailEntry(newEntry); } else { - _extra._entries.add(idx, newEntry); + getEntries().add(idx, newEntry); } } @@ -1230,9 +1243,15 @@ public class IndexPageCache public Entry remove(int idx) { return (isCurrentChildTailIndex(idx) ? setChildTailEntry(null) : - _extra._entries.remove(idx)); + getEntries().remove(idx)); } + @Override + public void clear() { + getEntries().clear(); + _childTailEntry = null; + } + public Entry setChildTailEntry(Entry newEntry) { Entry old = _childTailEntry; _childTailEntry = newEntry; @@ -1248,17 +1267,17 @@ public class IndexPageCache } private boolean isCurrentChildTailIndex(int idx) { - return(idx == _extra._entries.size()); + return(idx == getEntries().size()); } private boolean isNewChildTailIndex(int idx) { - return(idx == (_extra._entries.size() + 1)); + return(idx == (getEntries().size() + 1)); } public Entry getLast() { return(hasChildTail() ? _childTailEntry : - (!_extra._entries.isEmpty() ? - _extra._entries.get(_extra._entries.size() - 1) : null)); + (!getEntries().isEmpty() ? + getEntries().get(getEntries().size() - 1) : null)); } public int find(Entry e) { diff --git a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java index 73f1a9c..1a7ab87 100644 --- a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java +++ b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java @@ -98,7 +98,7 @@ public class BigIndexTest extends TestCase { System.out.println("BigIndexTest: Index type: " + index.getClass()); - // add 10,000 (pseudo) random entries to the table + // add 2,000 (pseudo) random entries to the table Random rand = new Random(13L); for(int i = 0; i < 2000; ++i) { int nextInt = rand.nextInt(Integer.MAX_VALUE); @@ -164,6 +164,26 @@ public class BigIndexTest extends TestCase { assertFalse(cursor.moveToNextRow()); assertFalse(cursor.moveToPreviousRow()); + ((BigIndex)index).validate(); + + // add 50 (pseudo) random entries to the table + rand = new Random(42L); + for(int i = 0; i < 50; ++i) { + int nextInt = rand.nextInt(Integer.MAX_VALUE); + String nextVal = "" + nextInt + extraText; + if(((i + 1) % 3333) == 0) { + nextVal = null; + } + t.addRow(nextVal, "this is some row data " + nextInt); + } + + ((BigIndex)index).validate(); + + cursor = Cursor.createIndexCursor(t, index); + while(cursor.moveToNextRow()) { + cursor.deleteCurrentRow(); + } + ((BigIndex)index).validate(); db.close(); -- 2.39.5