You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2015/03/05 16:21:14 UTC
svn commit: r1664377 - in /jackrabbit/oak/branches/1.0/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/
test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/
Author: thomasm
Date: Thu Mar 5 15:21:13 2015
New Revision: 1664377
URL: http://svn.apache.org/r1664377
Log:
OAK-2571 Protect the persistent cache against Thread.interrupt
Added:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheMap.java
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MapFactory.java
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/BlobCache.java
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MultiGenerationMap.java
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheTest.java
Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/BlobCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/BlobCache.java?rev=1664377&r1=1664376&r2=1664377&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/BlobCache.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/BlobCache.java Thu Mar 5 15:21:13 2015
@@ -20,7 +20,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -28,7 +27,7 @@ import javax.annotation.Nonnull;
import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCache.GenerationCache;
import org.apache.jackrabbit.oak.spi.blob.BlobStore;
import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
-import org.h2.mvstore.MVMapConcurrent;
+import org.h2.mvstore.MVMap;
import org.h2.mvstore.StreamStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,11 +59,11 @@ public class BlobCache implements BlobSt
@Override
public void addGeneration(int generation, boolean readOnly) {
- Map<Long, byte[]> d = cache.openMap(generation, "data",
- new MVMapConcurrent.Builder<Long, byte[]>());
+ CacheMap<Long, byte[]> d = cache.openMap(generation, "data",
+ new MVMap.Builder<Long, byte[]>());
data.addReadMap(generation, d);
- Map<String, byte[]> m = cache.openMap(generation, "meta",
- new MVMapConcurrent.Builder<String, byte[]>());
+ CacheMap<String, byte[]> m = cache.openMap(generation, "meta",
+ new MVMap.Builder<String, byte[]>());
meta.addReadMap(generation, m);
if (!readOnly) {
// the order is important:
Added: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheMap.java?rev=1664377&view=auto
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheMap.java (added)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheMap.java Thu Mar 5 15:21:13 2015
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.document.persistentCache;
+
+import java.util.Map;
+
+import org.h2.mvstore.MVMap;
+import org.h2.mvstore.MVMap.Builder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A cache map. This map supports re-opening the store if this is needed.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ */
+public class CacheMap<K, V> {
+
+ static final Logger LOG = LoggerFactory.getLogger(CacheMap.class);
+
+ private final MapFactory factory;
+ private final String name;
+ private final MVMap.Builder<K, V> builder;
+ private int openCount;
+ private volatile Map<K, V> map;
+ private volatile boolean closed;
+
+
+ public CacheMap(MapFactory factory, String name, Builder<K, V> builder) {
+ this.factory = factory;
+ this.name = name;
+ this.builder = builder;
+ openMap();
+ }
+
+ private void reopen(int i, Exception e) {
+ if (i > 10) {
+ LOG.warn("Too many re-opens; disabling this cache map", e);
+ closed = true;
+ return;
+ }
+ // clear the interrupt flag, to avoid re-opening many times
+ Thread.interrupted();
+ if (i == 0) {
+ LOG.warn("Re-opening map " + name, e);
+ } else {
+ LOG.debug("Re-opening map " + name + " again", e);
+ LOG.warn("Re-opening map " + name + " again");
+ }
+ openMap();
+ }
+
+ public V put(K key, V value) {
+ for (int i = 0;; i++) {
+ if (closed) {
+ return null;
+ }
+ try {
+ return map.put(key, value);
+ } catch (Exception e) {
+ reopen(i, e);
+ }
+ }
+ }
+
+ public V get(Object key) {
+ for (int i = 0;; i++) {
+ if (closed) {
+ return null;
+ }
+ try {
+ return map.get(key);
+ } catch (Exception e) {
+ reopen(i, e);
+ }
+ }
+ }
+
+ public boolean containsKey(Object key) {
+ for (int i = 0;; i++) {
+ if (closed) {
+ return false;
+ }
+ try {
+ return map.containsKey(key);
+ } catch (Exception e) {
+ reopen(i, e);
+ }
+ }
+ }
+
+ public V remove(Object key) {
+ for (int i = 0;; i++) {
+ if (closed) {
+ return null;
+ }
+ try {
+ return map.remove(key);
+ } catch (Exception e) {
+ reopen(i, e);
+ }
+ }
+ }
+
+ public void clear() {
+ for (int i = 0;; i++) {
+ if (closed) {
+ return;
+ }
+ try {
+ map.clear();
+ } catch (Exception e) {
+ reopen(i, e);
+ }
+ }
+ }
+
+ void openMap() {
+ openCount = factory.reopenStoreIfNeeded(openCount);
+ Map<K, V> m2 = factory.openMap(name, builder);
+ if (m2 != null) {
+ map = m2;
+ }
+ }
+
+}
Added: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MapFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MapFactory.java?rev=1664377&view=auto
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MapFactory.java (added)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MapFactory.java Thu Mar 5 15:21:13 2015
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.document.persistentCache;
+
+import java.util.Map;
+
+import org.h2.mvstore.MVMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class MapFactory {
+
+ static final Logger LOG = LoggerFactory.getLogger(MapFactory.class);
+
+ private int openCount = 1;
+
+ /**
+ * Ensure the store is open, re-opening it if needed. The store is first
+ * closed if the old open count if the old open count matches the current
+ * open count.
+ *
+ * @param oldOpenCount the old open count
+ * @return the new open count
+ */
+ synchronized int reopenStoreIfNeeded(int oldOpenCount) {
+ if (oldOpenCount == openCount) {
+ closeStore();
+ openCount++;
+ openStore();
+ }
+ return openCount;
+ }
+
+ public int getOpenCount() {
+ return openCount;
+ }
+
+ /**
+ * Open the store.
+ */
+ abstract void openStore();
+
+ /**
+ * Close the store.
+ */
+ abstract void closeStore();
+
+ /**
+ * Open or get the given map.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ * @param name the map name
+ * @param builder the map builder
+ * @return
+ */
+ abstract <K, V> Map<K, V> openMap(String name, MVMap.Builder<K, V> builder);
+
+ /**
+ * Get the file size in bytes.
+ *
+ * @return the file size
+ */
+ abstract long getFileSize();
+
+}
Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MultiGenerationMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MultiGenerationMap.java?rev=1664377&r1=1664376&r2=1664377&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MultiGenerationMap.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/MultiGenerationMap.java Thu Mar 5 15:21:13 2015
@@ -23,18 +23,18 @@ import java.util.concurrent.ConcurrentSk
public class MultiGenerationMap<K, V> implements Map<K, V> {
- private volatile Map<K, V> write;
- private ConcurrentSkipListMap<Integer, Map<K, V>> read =
- new ConcurrentSkipListMap<Integer, Map<K, V>>();
+ private volatile CacheMap<K, V> write;
+ private ConcurrentSkipListMap<Integer, CacheMap<K, V>> read =
+ new ConcurrentSkipListMap<Integer, CacheMap<K, V>>();
MultiGenerationMap() {
}
- public void setWriteMap(Map<K, V> m) {
+ public void setWriteMap(CacheMap<K, V> m) {
write = m;
}
- public void addReadMap(int generation, Map<K, V> m) {
+ public void addReadMap(int generation, CacheMap<K, V> m) {
read.put(generation, m);
}
@@ -51,7 +51,7 @@ public class MultiGenerationMap<K, V> im
@Override
public V get(Object key) {
for (int generation : read.descendingKeySet()) {
- Map<K, V> m = read.get(generation);
+ CacheMap<K, V> m = read.get(generation);
if (m != null) {
V value = m.get(key);
if (value != null) {
@@ -68,7 +68,7 @@ public class MultiGenerationMap<K, V> im
@Override
public boolean containsKey(Object key) {
for (int generation : read.descendingKeySet()) {
- Map<K, V> m = read.get(generation);
+ CacheMap<K, V> m = read.get(generation);
if (m != null) {
if (m.containsKey(key)) {
return true;
Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java?rev=1664377&r1=1664376&r2=1664377&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java Thu Mar 5 15:21:13 2015
@@ -26,7 +26,7 @@ import javax.annotation.Nullable;
import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCache.GenerationCache;
-import org.h2.mvstore.MVMapConcurrent;
+import org.h2.mvstore.MVMap;
import org.h2.mvstore.type.DataType;
import com.google.common.cache.Cache;
@@ -52,7 +52,7 @@ class NodeCache<K, V> implements Cache<K
this.type = type;
this.docNodeStore = docNodeStore;
this.docStore = docStore;
- PersistentCache.LOG.info("wrap " + this.type);
+ PersistentCache.LOG.info("wrapping map " + this.type);
map = new MultiGenerationMap<K, V>();
}
@@ -60,10 +60,10 @@ class NodeCache<K, V> implements Cache<K
public void addGeneration(int generation, boolean readOnly) {
DataType keyType = new KeyDataType(type);
DataType valueType = new ValueDataType(docNodeStore, docStore, type);
- MVMapConcurrent.Builder<K, V> b = new MVMapConcurrent.Builder<K, V>().
+ MVMap.Builder<K, V> b = new MVMap.Builder<K, V>().
keyType(keyType).valueType(valueType);
String mapName = type.name();
- Map<K, V> m = cache.openMap(generation, mapName, b);
+ CacheMap<K, V> m = cache.openMap(generation, mapName, b);
map.addReadMap(generation, m);
if (!readOnly) {
map.setWriteMap(m);
Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java?rev=1664377&r1=1664376&r2=1664377&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/PersistentCache.java Thu Mar 5 15:21:13 2015
@@ -25,7 +25,8 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
import org.h2.mvstore.FileStore;
-import org.h2.mvstore.MVMapConcurrent;
+import org.h2.mvstore.MVMap;
+import org.h2.mvstore.MVMap.Builder;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStoreTool;
import org.slf4j.Logger;
@@ -54,8 +55,8 @@ public class PersistentCache {
new ArrayList<GenerationCache>();
private final String directory;
- private MVStore writeStore;
- private MVStore readStore;
+ private MapFactory writeStore;
+ private MapFactory readStore;
private int maxSizeMB = 1024;
private int readGeneration = -1;
private int writeGeneration;
@@ -101,7 +102,7 @@ public class PersistentCache {
if (dir.length() == 0) {
readGeneration = -1;
writeGeneration = 0;
- writeStore = openStore(writeGeneration, false);
+ writeStore = createMapFactory(writeGeneration, false);
return;
}
File dr = new File(dir);
@@ -139,9 +140,9 @@ public class PersistentCache {
readGeneration = generations.size() > 1 ? generations.first() : -1;
writeGeneration = generations.size() > 0 ? generations.last() : 0;
if (readGeneration >= 0) {
- readStore = openStore(readGeneration, true);
+ readStore = createMapFactory(readGeneration, true);
}
- writeStore = openStore(writeGeneration, false);
+ writeStore = createMapFactory(writeGeneration, false);
}
private String getFileName(int generation) {
@@ -151,54 +152,108 @@ public class PersistentCache {
return directory + "/" + FILE_PREFIX + generation + FILE_SUFFIX;
}
- private MVStore openStore(int generation, boolean readOnly) {
- String fileName = getFileName(generation);
- MVStore.Builder builder = new MVStore.Builder();
- if (compress) {
- builder.compress();
- }
- if (fileName != null) {
- builder.fileName(fileName);
- }
- if (readOnly) {
- builder.readOnly();
- }
- if (maxSizeMB < 10) {
- builder.cacheSize(maxSizeMB);
- }
- if (autoCompact >= 0) {
- builder.autoCompactFillRate(autoCompact);
- }
- builder.backgroundExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ private MapFactory createMapFactory(final int generation, final boolean readOnly) {
+ MapFactory f = new MapFactory() {
+
+ final String fileName = getFileName(generation);
+ MVStore store;
+
@Override
- public void uncaughtException(Thread t, Throwable e) {
- LOG.error("Error in persistent cache", e);
+ void openStore() {
+ if (store != null) {
+ return;
+ }
+ MVStore.Builder builder = new MVStore.Builder();
+ try {
+ if (compress) {
+ builder.compress();
+ }
+ if (fileName != null) {
+ builder.fileName(fileName);
+ }
+ if (readOnly) {
+ builder.readOnly();
+ }
+ if (maxSizeMB < 10) {
+ builder.cacheSize(maxSizeMB);
+ }
+ if (autoCompact >= 0) {
+ builder.autoCompactFillRate(autoCompact);
+ }
+ builder.backgroundExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(Thread t, Throwable e) {
+ LOG.debug("Error in the background thread of the persistent cache", e);
+ LOG.warn("Error in the background thread of the persistent cache: " + e);
+ }
+ });
+ store = builder.open();
+ if (appendOnly) {
+ store.setReuseSpace(false);
+ }
+ } catch (Exception e) {
+ LOG.warn("Could not open the store " + fileName, e);
+ }
}
- });
- MVStore store = builder.open();
- if (appendOnly) {
- store.setReuseSpace(false);
- }
- return store;
+
+ @Override
+ synchronized void closeStore() {
+ if (store == null) {
+ return;
+ }
+ try {
+ boolean compact = compactOnClose;
+ if (store.getFileStore().isReadOnly()) {
+ compact = false;
+ }
+ store.close();
+ if (compact) {
+ MVStoreTool.compact(fileName, true);
+ }
+ } catch (Exception e) {
+ LOG.debug("Could not close or compact the store", e);
+ LOG.warn("Could not close or compact the store: " + e);
+ }
+ store = null;
+ }
+
+ @Override
+ <K, V> Map<K, V> openMap(String name, Builder<K, V> builder) {
+ try {
+ if (builder == null) {
+ return store.openMap(name);
+ }
+ return store.openMap(name, builder);
+ } catch (Exception e) {
+ LOG.warn("Could not open the map", e);
+ return null;
+ }
+ }
+
+ @Override
+ long getFileSize() {
+ try {
+ FileStore fs = store.getFileStore();
+ if (fs == null) {
+ return 0;
+ }
+ return fs.size();
+ } catch (Exception e) {
+ LOG.warn("Could not retrieve the map size", e);
+ return 0;
+ }
+ }
+ };
+ f.openStore();
+ return f;
}
public void close() {
- closeStore(writeStore, writeGeneration);
- closeStore(readStore, readGeneration);
- }
-
- private void closeStore(MVStore s, int generation) {
- if (s == null) {
- return;
+ if (writeStore != null) {
+ writeStore.closeStore();
}
- String fileName = getFileName(generation);
- boolean compact = compactOnClose;
- if (s.getFileStore().isReadOnly()) {
- compact = false;
- }
- s.close();
- if (compact) {
- MVStoreTool.compact(fileName, true);
+ if (readStore != null) {
+ readStore.closeStore();
}
}
@@ -250,9 +305,9 @@ public class PersistentCache {
c.addGeneration(writeGeneration, false);
}
- synchronized <K, V> Map<K, V> openMap(int generation, String name,
- MVMapConcurrent.Builder<K, V> builder) {
- MVStore s;
+ public synchronized <K, V> CacheMap<K, V> openMap(int generation, String name,
+ MVMap.Builder<K, V> builder) {
+ MapFactory s;
if (generation == readGeneration) {
s = readStore;
} else if (generation == writeGeneration) {
@@ -260,7 +315,7 @@ public class PersistentCache {
} else {
throw new IllegalArgumentException("Unknown generation: " + generation);
}
- return s.openMap(name, builder);
+ return new CacheMap<K, V>(s, name, builder);
}
public void switchGenerationIfNeeded() {
@@ -274,10 +329,10 @@ public class PersistentCache {
return;
}
int oldReadGeneration = readGeneration;
- MVStore oldRead = readStore;
+ MapFactory oldRead = readStore;
readStore = writeStore;
readGeneration = writeGeneration;
- MVStore w = openStore(writeGeneration + 1, false);
+ MapFactory w = createMapFactory(writeGeneration + 1, false);
writeStore = w;
writeGeneration++;
for (GenerationCache c : caches) {
@@ -287,18 +342,14 @@ public class PersistentCache {
}
}
if (oldRead != null) {
- oldRead.close();
+ oldRead.closeStore();
new File(getFileName(oldReadGeneration)).delete();
}
}
}
private boolean needSwitch() {
- FileStore fs = writeStore.getFileStore();
- if (fs == null) {
- return false;
- }
- long size = fs.size();
+ long size = writeStore.getFileSize();
if (size / 1024 / 1024 <= maxSizeMB) {
return false;
}
@@ -312,6 +363,11 @@ public class PersistentCache {
public long getMaxBinaryEntrySize() {
return maxBinaryEntry;
}
+
+ public int getOpenCount() {
+ return writeStore.getOpenCount();
+ }
+
interface GenerationCache {
Modified: jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheTest.java?rev=1664377&r1=1664376&r2=1664377&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheTest.java (original)
+++ jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheTest.java Thu Mar 5 15:21:13 2015
@@ -18,9 +18,14 @@
*/
package org.apache.jackrabbit.oak.plugins.document.persistentCache;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
import java.io.ByteArrayInputStream;
+import java.io.File;
import java.util.Random;
+import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.oak.spi.blob.BlobStore;
import org.apache.jackrabbit.oak.spi.blob.MemoryBlobStore;
import org.junit.Test;
@@ -29,18 +34,62 @@ public class CacheTest {
@Test
public void test() throws Exception {
+ FileUtils.deleteDirectory(new File("target/cacheTest"));
+ PersistentCache cache = new PersistentCache("target/cacheTest,size=1,-compress");
+ try {
+ MemoryBlobStore mem = new MemoryBlobStore();
+ mem.setBlockSizeMin(100);
+ BlobStore b = cache.wrapBlobStore(mem);
+ Random r = new Random();
+ for (int i = 0; i < 10000; i++) {
+ byte[] data = new byte[100];
+ r.nextBytes(data);
+ String id = b.writeBlob(new ByteArrayInputStream(data));
+ b.readBlob(id, 0, new byte[1], 0, 1);
+ }
+ } finally {
+ cache.close();
+ }
+ }
+
+ @Test
+ public void interrupt() throws Exception {
+ FileUtils.deleteDirectory(new File("target/cacheTest"));
PersistentCache cache = new PersistentCache("target/cacheTest,size=1,-compress");
- MemoryBlobStore mem = new MemoryBlobStore();
- mem.setBlockSizeMin(100);
- BlobStore b = cache.wrapBlobStore(mem);
- Random r = new Random();
- for(int i=0; i<10000; i++) {
- byte[] data = new byte[100];
- r.nextBytes(data);
- String id = b.writeBlob(new ByteArrayInputStream(data));
- b.readBlob(id, 0, new byte[1], 0, 1);
+ try {
+ CacheMap<String, String> m1 = cache.openMap(0, "m1", null);
+ CacheMap<String, String> m2 = cache.openMap(0, "test", null);
+
+ // the cache file was opened once so far
+ assertEquals(1, cache.getOpenCount());
+
+ // we store 20 mb of data, to ensure not all data is kept in memory
+ String largeString = new String(new char[1024 * 1024]);
+ int count = 10;
+ for (int i = 0; i < count; i++) {
+ m1.put("x" + i, largeString);
+ m2.put("y" + i, largeString);
+ }
+
+ // interrupt the thread, which will cause the FileChannel
+ // to be closed in the next read operation
+ Thread.currentThread().interrupt();
+
+ // this will force at least one read operation,
+ // which should re-open the maps
+ for (int i = 0; i < count; i++) {
+ m1.get("x" + i);
+ m2.get("y" + i);
+ }
+
+ assertEquals(2, cache.getOpenCount());
+
+ // re-opening will clear the interrupt flag
+ assertFalse(Thread.interrupted());
+
+ } finally {
+ cache.close();
}
- cache.close();
}
}