diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2013-06-17 01:59:21 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2013-06-17 01:59:21 +0000 |
commit | 08a343c1e2072eebf97288a13bdd75c8885ebd42 (patch) | |
tree | bc54b857dd01722e47926beac8e4907ae19a1a24 | |
parent | 0499f0bcbb095b5cf964bab36b56ad2c230ac1fe (diff) | |
download | jackcess-08a343c1e2072eebf97288a13bdd75c8885ebd42.tar.gz jackcess-08a343c1e2072eebf97288a13bdd75c8885ebd42.zip |
limit size of indexpagecache
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/jackcess-2@738 f203690c-595d-4dc9-a70b-905162fa7fd2
3 files changed, 65 insertions, 18 deletions
diff --git a/src/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java b/src/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java index ef585db..325e178 100644 --- a/src/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java +++ b/src/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java @@ -33,13 +33,12 @@ import java.lang.ref.SoftReference; import java.util.AbstractList; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.RandomAccess; - import static com.healthmarketscience.jackcess.impl.IndexData.*; /** @@ -52,13 +51,29 @@ public class IndexPageCache ADD, REMOVE, REPLACE; } + /** max number of pages to cache (unless a write operation is in + progress) */ + private static final int MAX_CACHE_SIZE = 25; + /** the index whose pages this cache is managing */ private final IndexData _indexData; /** the root page for the index */ private DataPageMain _rootPage; /** the currently loaded pages for this index, pageNumber -> page */ private final Map<Integer, DataPageMain> _dataPages = - new HashMap<Integer, DataPageMain>(); + new LinkedHashMap<Integer, DataPageMain>(16, 0.75f, true) { + private static final long serialVersionUID = 0L; + @Override + protected boolean removeEldestEntry(Map.Entry<Integer, DataPageMain> e) { + // only purge when the size is too big and a logical write operation is + // not in progress (while an update is happening, the pages can be in + // flux and removing pages from the cache can cause problems) + if((size() > MAX_CACHE_SIZE) && !getPageChannel().isWriting()) { + purgeOldPages(); + } + return false; + } + }; /** the currently modified index pages */ private final List<CacheDataPage> _modifiedPages = new ArrayList<CacheDataPage>(); @@ -74,7 +89,7 @@ public class IndexPageCache public PageChannel getPageChannel() { return getIndexData().getPageChannel(); } - + /** * Sets the root page for this index, must be called before normal usage. * @@ -98,6 +113,10 @@ public class IndexPageCache preparePagesForWriting(); // finally, write all the modified pages (which are not being deleted) writeDataPages(); + // after we write everything, we can purge our cache if necessary + if(_dataPages.size() > MAX_CACHE_SIZE) { + purgeOldPages(); + } } /** @@ -645,7 +664,7 @@ public class IndexPageCache // insert this new page between the old page and any previous page addToPeersBefore(newDataPage, origDataPage); - + if(!newMain._leaf) { // reparent the children pages of the new page reparentChildren(newDataPage); @@ -965,7 +984,8 @@ public class IndexPageCache * Used by unit tests to validate the internal status of the index. */ void validate() throws IOException { - for(DataPageMain dpMain : _dataPages.values()) { + // copy the values as the validation methods might trigger map updates + for(DataPageMain dpMain : new ArrayList<DataPageMain>(_dataPages.values())) { DataPageExtra dpExtra = dpMain.getExtra(); validateEntries(dpExtra); validateChildren(dpMain, dpExtra); @@ -1107,6 +1127,24 @@ public class IndexPageCache rtn.append("Page[" + dpMain._pageNumber + "]: " + e); } } + + /** + * Trims the size of the _dataPages cache appropriately (assuming caller has + * already verified that the cache needs trimming). + */ + private void purgeOldPages() { + Iterator<DataPageMain> iter = _dataPages.values().iterator(); + while(iter.hasNext()) { + DataPageMain dpMain = iter.next(); + // note, we never purge the root page + if(dpMain != _rootPage) { + iter.remove(); + if(_dataPages.size() <= MAX_CACHE_SIZE) { + break; + } + } + } + } @Override public String toString() { @@ -1224,7 +1262,7 @@ public class IndexPageCache return extra; } - + public void setExtra(DataPageExtra extra) throws IOException { extra.setEntryView(this); diff --git a/src/java/com/healthmarketscience/jackcess/impl/PageChannel.java b/src/java/com/healthmarketscience/jackcess/impl/PageChannel.java index 03611da..d3d5367 100644 --- a/src/java/com/healthmarketscience/jackcess/impl/PageChannel.java +++ b/src/java/com/healthmarketscience/jackcess/impl/PageChannel.java @@ -154,6 +154,23 @@ public class PageChannel implements Channel, Flushable { flush(); } } + + /** + * Returns {@code true} if a logical write operation is in progress, {@code + * false} otherwise. + */ + public boolean isWriting() { + return(_writeCount > 0); + } + + /** + * Asserts that a write operation is in progress. + */ + private void assertWriting() { + if(!isWriting()) { + throw new IllegalStateException("No write operation in progress"); + } + } /** * Returns the next page number based on the given file size. @@ -387,15 +404,6 @@ public class PageChannel implements Channel, Flushable { buffer.put(pos, b); } } - - /** - * Asserts that a write operation is in progress. - */ - private void assertWriting() { - if(_writeCount <= 0) { - throw new IllegalStateException("No write operation in progress"); - } - } /** * @return a duplicate of the current buffer narrowed to the given position diff --git a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java index 7661d54..70d63d8 100644 --- a/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java +++ b/test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java @@ -44,8 +44,6 @@ import com.healthmarketscience.jackcess.impl.IndexImpl; */ public class BigIndexTest extends TestCase { - private String _oldBigIndexValue = null; - public BigIndexTest(String name) { super(name); } @@ -116,6 +114,9 @@ public class BigIndexTest extends TestCase { index.getIndexData().validate(); db.flush(); + t = null; + System.gc(); + t = (TableImpl)db.getTable("Table1"); index = t.getIndex("col1"); |