aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2013-06-17 01:59:21 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2013-06-17 01:59:21 +0000
commit08a343c1e2072eebf97288a13bdd75c8885ebd42 (patch)
treebc54b857dd01722e47926beac8e4907ae19a1a24
parent0499f0bcbb095b5cf964bab36b56ad2c230ac1fe (diff)
downloadjackcess-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
-rw-r--r--src/java/com/healthmarketscience/jackcess/impl/IndexPageCache.java52
-rw-r--r--src/java/com/healthmarketscience/jackcess/impl/PageChannel.java26
-rw-r--r--test/src/java/com/healthmarketscience/jackcess/BigIndexTest.java5
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");