summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/changes/changes.xml2
-rw-r--r--src/java/com/healthmarketscience/jackcess/IndexPageCache.java113
-rw-r--r--test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java30
3 files changed, 64 insertions, 81 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 7f14205..bd8f25a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -15,7 +15,7 @@
</action>
<action dev="jahlborn" type="fix" issue="1564870">
Added experimental support for "large" indexes. The current support
- is optional. It can be enabled via a varity of means, see the
+ is optional. It can be enabled via a variety of means, see the
Database javadoc for more details.
</action>
</release>
diff --git a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java
index 2fc8617..d1a9561 100644
--- a/src/java/com/healthmarketscience/jackcess/IndexPageCache.java
+++ b/src/java/com/healthmarketscience/jackcess/IndexPageCache.java
@@ -71,10 +71,6 @@ public class IndexPageCache
return _index;
}
- public JetFormat getFormat() {
- return getIndex().getFormat();
- }
-
public PageChannel getPageChannel() {
return getIndex().getPageChannel();
}
@@ -119,8 +115,8 @@ public class IndexPageCache
do {
splitPages = false;
- // we might be adding to this list while iterating, so we can't use an
- // iteratoor
+ // we might be adding to this list while iterating, so we can't use an
+ // iterator
for(int i = 0; i < _modifiedPages.size(); ++i) {
CacheDataPage cacheDataPage = _modifiedPages.get(i);
@@ -261,14 +257,6 @@ public class IndexPageCache
updateEntry(cacheDataPage, entryIdx, newEntry, UpdateType.ADD);
}
- private void replaceEntry(CacheDataPage cacheDataPage,
- int entryIdx,
- Entry newEntry)
- throws IOException
- {
- updateEntry(cacheDataPage, entryIdx, newEntry, UpdateType.REPLACE);
- }
-
private void updateEntry(CacheDataPage cacheDataPage,
int entryIdx,
Entry newEntry,
@@ -282,6 +270,12 @@ public class IndexPageCache
validateEntryForPage(dpMain, newEntry);
}
+ // note, it's slightly ucky, but we need to load the parent page before we
+ // start mucking with our entries because our parent may use our entries.
+ CacheDataPage parentDataPage = (!dpMain.isRoot() ?
+ new CacheDataPage(dpMain.getParentPage()) :
+ null);
+
Entry oldLastEntry = dpExtra._entryView.getLast();
Entry oldEntry = null;
int entrySizeDiff = 0;
@@ -319,7 +313,7 @@ public class IndexPageCache
if(dpExtra._entryView.isEmpty()) {
// this page is dead
- removeDataPage(cacheDataPage, oldLastEntry);
+ removeDataPage(parentDataPage, cacheDataPage, oldLastEntry);
return;
}
@@ -330,11 +324,11 @@ public class IndexPageCache
}
// the update to the last entry needs to be propagated to our parent
- replaceParentEntry(new CacheDataPage(dpMain.getParentPage()),
- cacheDataPage, oldLastEntry);
+ replaceParentEntry(parentDataPage, cacheDataPage, oldLastEntry);
}
- private void removeDataPage(CacheDataPage cacheDataPage,
+ private void removeDataPage(CacheDataPage parentDataPage,
+ CacheDataPage cacheDataPage,
Entry oldLastEntry)
throws IOException
{
@@ -360,8 +354,8 @@ public class IndexPageCache
}
// remove this page from its parent page
- updateParentEntry(new CacheDataPage(dpMain.getParentPage()),
- cacheDataPage, oldLastEntry, null, UpdateType.REMOVE);
+ updateParentEntry(parentDataPage, cacheDataPage, oldLastEntry, null,
+ UpdateType.REMOVE);
// remove this page from any next/prev pages
removeFromPeers(cacheDataPage);
@@ -388,16 +382,6 @@ public class IndexPageCache
}
}
- private void removeParentEntry(CacheDataPage childDataPage)
- throws IOException
- {
- DataPageMain childMain = childDataPage._main;
- DataPageExtra childExtra = childDataPage._extra;
- updateParentEntry(new CacheDataPage(childMain.getParentPage()),
- childDataPage, childExtra._entryView.getLast(),
- null, UpdateType.REMOVE);
- }
-
private void addParentEntry(CacheDataPage parentDataPage,
CacheDataPage childDataPage)
throws IOException
@@ -464,10 +448,6 @@ public class IndexPageCache
"; parent " + parentDataPage);
}
idx = missingIndexToInsertionPoint(idx);
- if(childMain.isTail() && (upType == UpdateType.ADD)) {
- // we add a tail entry by using the index (size + 1)
- ++idx;
- }
} else {
if(!expectFound) {
throw new IllegalStateException(
@@ -516,6 +496,8 @@ public class IndexPageCache
DataPageMain origMain = origDataPage._main;
DataPageExtra origExtra = origDataPage._extra;
+ setModified(origDataPage);
+
int numEntries = origExtra._entries.size();
if(numEntries < 2) {
throw new IllegalStateException(
@@ -533,11 +515,15 @@ public class IndexPageCache
origExtra = newDataPage._extra;
}
+ // note, it's slightly ucky, but we need to load the parent page before we
+ // start mucking with our entries because our parent may use our entries.
+ DataPageMain parentMain = origMain.getParentPage();
+ CacheDataPage parentDataPage = new CacheDataPage(parentMain);
+
// note, there are many, many ways this could be improved/tweaked. for
// now, we just want it to be functional...
// so, we will naively move half the entries from one page to a new page.
- DataPageMain parentMain = origMain.getParentPage();
CacheDataPage newDataPage = allocateNewCacheDataPage(
parentMain._pageNumber, origMain._leaf);
DataPageMain newMain = newDataPage._main;
@@ -577,7 +563,6 @@ public class IndexPageCache
}
// lastly, we need to add the new page to the parent page's entries
- CacheDataPage parentDataPage = new CacheDataPage(parentMain);
addParentEntry(parentDataPage, newDataPage);
}
@@ -707,18 +692,18 @@ public class IndexPageCache
DataPageMain dpMain = cacheDataPage._main;
DataPageExtra dpExtra = cacheDataPage._extra;
+ setModified(cacheDataPage);
+
DataPageMain tailMain = dpMain.getChildTailPage();
CacheDataPage tailDataPage = new CacheDataPage(tailMain);
- // 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
+ // move the tail entry to the last normal entry
updateParentTail(cacheDataPage, tailDataPage, UpdateType.REMOVE);
- dpExtra._entryView.clear();
+ Entry tailEntry = dpExtra._entryView.demoteTail();
+ dpExtra._totalEntrySize += tailEntry.size();
+ dpExtra._entryPrefix = EMPTY_PREFIX;
tailMain.setParentPage(dpMain._pageNumber, false);
-
- addParentEntry(cacheDataPage, tailDataPage);
}
private void promoteTail(CacheDataPage cacheDataPage)
@@ -728,13 +713,18 @@ public class IndexPageCache
DataPageMain dpMain = cacheDataPage._main;
DataPageExtra dpExtra = cacheDataPage._extra;
+ setModified(cacheDataPage);
+
DataPageMain lastMain = dpMain.getChildPage(dpExtra._entryView.getLast());
CacheDataPage lastDataPage = new CacheDataPage(lastMain);
- removeParentEntry(lastDataPage);
-
- lastMain.setParentPage(dpMain._pageNumber, true);
- addParentEntry(cacheDataPage, lastDataPage);
+ // move the "last" normal entry to the tail entry
+ updateParentTail(cacheDataPage, lastDataPage, UpdateType.ADD);
+ Entry lastEntry = dpExtra._entryView.promoteTail();
+ dpExtra._totalEntrySize -= lastEntry.size();
+ dpExtra._entryPrefix = EMPTY_PREFIX;
+
+ lastMain.setParentPage(dpMain._pageNumber, true);
}
public CacheDataPage findCacheDataPage(Entry e)
@@ -1232,11 +1222,9 @@ public class IndexPageCache
@Override
public void add(int idx, Entry newEntry) {
- if(isNewChildTailIndex(idx)) {
- setChildTailEntry(newEntry);
- } else {
- getEntries().add(idx, newEntry);
- }
+ // note, we will never add to the "tail" entry, that will always be
+ // handled through promoteTail
+ getEntries().add(idx, newEntry);
}
@Override
@@ -1245,12 +1233,6 @@ public class IndexPageCache
setChildTailEntry(null) :
getEntries().remove(idx));
}
-
- @Override
- public void clear() {
- getEntries().clear();
- _childTailEntry = null;
- }
public Entry setChildTailEntry(Entry newEntry) {
Entry old = _childTailEntry;
@@ -1270,16 +1252,25 @@ public class IndexPageCache
return(idx == getEntries().size());
}
- private boolean isNewChildTailIndex(int idx) {
- return(idx == (getEntries().size() + 1));
- }
-
public Entry getLast() {
return(hasChildTail() ? _childTailEntry :
(!getEntries().isEmpty() ?
getEntries().get(getEntries().size() - 1) : null));
}
+ public Entry demoteTail() {
+ Entry tail = _childTailEntry;
+ _childTailEntry = null;
+ getEntries().add(tail);
+ return tail;
+ }
+
+ public Entry promoteTail() {
+ Entry last = getEntries().remove(getEntries().size() - 1);
+ _childTailEntry = last;
+ return last;
+ }
+
public int find(Entry e) {
return Collections.binarySearch(this, e);
}
diff --git a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java
index 1a7ab87..522148e 100644
--- a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java
+++ b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java
@@ -89,7 +89,7 @@ public class BigIndexTest extends TestCase {
DatabaseTest._autoSync = false;
try {
- String extraText = " some random text to fill out the index and make it fill up pages";
+ String extraText = " some random text to fill out the index and make it fill up pages with lots of extra bytes so i will keep typing until i think that i probably have enough text in the index entry so that i do not need to add as many entries in order";
// copy to temp file and attempt to edit
db = openCopy(origFile);
@@ -137,9 +137,16 @@ public class BigIndexTest extends TestCase {
((BigIndex)index).validate();
- // remove all but the first two entries
- Cursor cursor = new CursorBuilder(t).setIndex(index)
- .afterLast().toCursor();
+ // delete an entry in the middle
+ Cursor cursor = Cursor.createIndexCursor(t, index);
+ for(int i = 0; i < (rowCount / 2); ++i) {
+ assertTrue(cursor.moveToNextRow());
+ }
+ cursor.deleteCurrentRow();
+ --rowCount;
+
+ // remove all but the first two entries (from the end)
+ cursor.afterLast();
for(int i = 0; i < (rowCount - 2); ++i) {
assertTrue(cursor.moveToPreviousRow());
cursor.deleteCurrentRow();
@@ -193,19 +200,4 @@ public class BigIndexTest extends TestCase {
}
}
-// public void testBigIndex2() throws Exception
-// {
-// File f = new File("test/data/databaseTest19731_ind.mdb");
-// Database db = open(f);
-// Table t = db.getTable("test");
-// System.out.println("FOO reading index");
-// Index index = t.getIndexes().get(0);
-// index.initialize();
-// index.forceInit();
-// index.validate();
-// System.out.println(index);
-// db.close();
-// }
-
-
}