Author: mreutegg
Date: Tue Jul 21 10:25:04 2015
New Revision: 1692079
URL: http://svn.apache.org/r1692079
Log:
OAK-3112: Performance degradation of UnsavedModifications on MapDB
Added:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java
(with props)
Modified:
jackrabbit/oak/branches/1.0/RELEASE-NOTES.txt
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactory.java
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapFactory.java
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactoryTest.java
Modified: jackrabbit/oak/branches/1.0/RELEASE-NOTES.txt
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/RELEASE-NOTES.txt?rev=1692079&r1=1692078&r2=1692079&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.0/RELEASE-NOTES.txt (original)
+++ jackrabbit/oak/branches/1.0/RELEASE-NOTES.txt Tue Jul 21 10:25:04 2015
@@ -21,6 +21,10 @@ New configuration options in Oak 1.0.18
Support for pre extracting text to speed up reindexing has been added in
OAK-2892
For more details refer to
http://jackrabbit.apache.org/oak/docs/query/lucene.html#text-extraction
+For DocumentNodeStore based deployments a new MapFactory implementation has
+been introduced and can be enabled with -Doak.useHybridMapFactory=true
+See OAK-3112 for details.
+
Changes in Oak 1.0.18
---------------------
Added:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java?rev=1692079&view=auto
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java
(added)
+++
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java
Tue Jul 21 10:25:04 2015
@@ -0,0 +1,345 @@
+/*
+ * 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.util;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ForwardingConcurrentMap;
+import com.google.common.collect.Maps;
+
+import org.apache.jackrabbit.oak.plugins.document.Revision;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A hybrid MapFactory implementation switching from an in-memory map to a
+ * MapDB backed map when the size of the map reaches a threshold. Once the
+ * map shrinks again, the implementation switches back to an in-memory map.
+ *
+ * This factory implementation keeps track of maps created by {@link #create()}
+ * and {@link #create(Comparator)} with weak references and disposes the
+ * underlying {@link MapDBMapFactory} when a map created by that factory is not
+ * referenceable and not in use anymore.
+ */
+public class HybridMapFactory extends MapFactory {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(HybridMapFactory.class);
+
+ /**
+ * Keep at most this number of entries in memory, otherwise use a map
+ * implementation backed by MapDB.
+ */
+ static final int IN_MEMORY_SIZE_LIMIT = 100000;
+
+ /**
+ * Switch to an in-memory map when there are less than 10'000 entries
+ * in the map.
+ */
+ static final int IN_MEMORY_SIZE_LIMIT_LOW = 10000;
+
+ /**
+ * Reference queue for maps backed by MapDB.
+ */
+ private final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+
+ /**
+ * Maps {@link MapReference}s to their corresponding MapFactory.
+ */
+ private final Map<Reference, MapFactory> factories =
Maps.newIdentityHashMap();
+
+ @Override
+ public ConcurrentMap<String, Revision> create() {
+ return create(null);
+ }
+
+ @Override
+ public ConcurrentMap<String, Revision> create(Comparator<String>
comparator) {
+ return new MapImpl(comparator);
+ }
+
+ @Override
+ public void dispose() {
+ for (MapFactory f : factories.values()) {
+ dispose(f);
+ }
+ factories.clear();
+ }
+
+ //------------------------------< internal
>--------------------------------
+
+ private synchronized void pollReferenceQueue() {
+ Reference ref;
+ while ((ref = queue.poll()) != null) {
+ dispose(factories.remove(ref));
+ }
+ }
+
+ private void dispose(MapFactory factory) {
+ try {
+ if (factory != null) {
+ Stopwatch sw = Stopwatch.createStarted();
+ factory.dispose();
+ sw.stop();
+ LOG.debug("Disposed MapDB map in {}", sw);
+ }
+ } catch (Exception e) {
+ LOG.warn("Failed to dispose MapFactory", e);
+ }
+ }
+
+ /**
+ * A map implementation, which forwards calls to either an in-memory or
+ * MapDB backed map implementation. Methods, which modify the underlying
map
+ * are synchronized because of OAK-2888.
+ */
+ private final class MapImpl extends
+ ForwardingConcurrentMap<String, Revision> {
+
+ /**
+ * A comparator, if keys of the map are sorted, otherwise {@code null}.
+ */
+ private final Comparator<String> comparator;
+
+ /**
+ * The current map. This is either in-memory or a map backed by MapDB.
+ */
+ private volatile ConcurrentMap<String, Revision> map;
+
+ /**
+ * Maintain size of {@link #map} because the in-memory MapFactory
+ * variant uses a ConcurrentSkipListMap with a non-constant size()
cost.
+ */
+ private long size;
+
+ /**
+ * Whether the current {@link #map} is in memory.
+ */
+ private boolean mapInMemory;
+
+ MapImpl(@Nullable Comparator<String> comparator) {
+ this.comparator = comparator;
+ this.map = createMap(true);
+ this.mapInMemory = true;
+ }
+
+ @Override
+ protected ConcurrentMap<String, Revision> delegate() {
+ return map;
+ }
+
+ @Override
+ public synchronized Revision putIfAbsent(@Nonnull String key,
+ @Nonnull Revision value) {
+ Revision r = map.putIfAbsent(key, checkNotNull(value));
+ if (r == null) {
+ size++;
+ maybeSwitchToMapDB();
+ }
+ return r;
+ }
+
+ @Override
+ public synchronized Revision put(@Nonnull String key, @Nonnull
Revision value) {
+ Revision r = map.put(key, checkNotNull(value));
+ if (r == null) {
+ size++;
+ maybeSwitchToMapDB();
+ }
+ return r;
+ }
+
+ @Override
+ public synchronized void putAll(@Nonnull Map<? extends String, ?
extends Revision> map) {
+ for (Map.Entry<? extends String, ? extends Revision> entry :
map.entrySet()) {
+ if (this.map.put(entry.getKey(),
checkNotNull(entry.getValue())) == null) {
+ size++;
+ maybeSwitchToMapDB();
+ }
+ }
+ }
+
+ @Override
+ public synchronized boolean remove(@Nonnull Object key,
+ @Nonnull Object value) {
+ boolean remove = map.remove(key, value);
+ if (remove) {
+ size--;
+ maybeSwitchToInMemoryMap();
+ }
+ return remove;
+ }
+
+ @Override
+ public synchronized Revision remove(@Nonnull Object object) {
+ Revision r = map.remove(object);
+ if (r != null) {
+ size--;
+ maybeSwitchToInMemoryMap();
+ }
+ return r;
+ }
+
+ @Override
+ public synchronized Revision replace(@Nonnull String key,
+ @Nonnull Revision value) {
+ return map.replace(key, checkNotNull(value));
+ }
+
+ @Override
+ public synchronized boolean replace(@Nonnull String key,
+ @Nonnull Revision oldValue,
+ @Nonnull Revision newValue) {
+ return map.replace(key, checkNotNull(oldValue),
checkNotNull(newValue));
+ }
+
+ @Override
+ public synchronized void clear() {
+ map.clear();
+ size = 0;
+ }
+
+ @Nonnull
+ @Override
+ public Collection<Revision> values() {
+ return Collections.unmodifiableCollection(map.values());
+ }
+
+ @Nonnull
+ @Override
+ public Set<Entry<String, Revision>> entrySet() {
+ return Collections.unmodifiableSet(map.entrySet());
+ }
+
+ @Nonnull
+ @Override
+ public Set<String> keySet() {
+ return Collections.unmodifiableSet(map.keySet());
+ }
+
+ private void maybeSwitchToMapDB() {
+ // switch map if
+ // - map is currently in-memory
+ // - size limit is reached
+ if (mapInMemory
+ && size >= IN_MEMORY_SIZE_LIMIT) {
+ Stopwatch sw = Stopwatch.createStarted();
+ ConcurrentMap<String, Revision> tmp = createMap(false);
+ tmp.putAll(map);
+ map = tmp;
+ mapInMemory = false;
+ sw.stop();
+ LOG.debug("Switched to MapDB map in {}", sw);
+ pollReferenceQueue();
+ }
+ }
+
+ private void maybeSwitchToInMemoryMap() {
+ // only switch to in memory if not already in memory
+ // and size is less than lower limit
+ if (!mapInMemory && size < IN_MEMORY_SIZE_LIMIT_LOW) {
+ Stopwatch sw = Stopwatch.createStarted();
+ ConcurrentMap<String, Revision> tmp = createMap(true);
+ tmp.putAll(map);
+ map = tmp;
+ mapInMemory = true;
+ sw.stop();
+ LOG.debug("Switched to in-memory map in {}", sw);
+ pollReferenceQueue();
+ }
+ }
+
+ private ConcurrentMap<String, Revision> createMap(boolean inMemory) {
+ MapFactory f;
+ if (inMemory) {
+ f = MapFactory.DEFAULT;
+ } else {
+ f = new MapDBMapFactory();
+ }
+ ConcurrentMap<String, Revision> map;
+ if (comparator != null) {
+ map = f.create(comparator);
+ } else {
+ map = f.create();
+ }
+ if (!inMemory) {
+ map = new MapDBWrapper(map);
+ factories.put(new MapReference(map, queue), f);
+ }
+ return map;
+ }
+ }
+
+ /**
+ * A map wrapper implementation forwarding calls to a MapDB backed map
+ * implementation. Instances of this class are tracked with weak references
+ * and the corresponding {@link MapDBMapFactory} is disposed when there
+ * are no more references to a MapDBWrapper. This also includes collections
+ * obtained from this map, e.g. {@link #entrySet()}, {@link #values()} or
+ * {@link #keySet()}.
+ *
+ */
+ private static final class MapDBWrapper extends
ForwardingConcurrentMap<String, Revision> {
+
+ private final ConcurrentMap<String, Revision> map;
+
+ protected MapDBWrapper(@Nonnull ConcurrentMap<String, Revision> map) {
+ this.map = checkNotNull(map);
+ }
+
+ @Override
+ protected ConcurrentMap<String, Revision> delegate() {
+ return map;
+ }
+
+ @Override
+ public Set<Entry<String, Revision>> entrySet() {
+ return Collections.unmodifiableSet(map.entrySet());
+ }
+
+ @Override
+ public Collection<Revision> values() {
+ return Collections.unmodifiableCollection(map.values());
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return Collections.unmodifiableSet(map.keySet());
+ }
+ }
+
+ private static final class MapReference extends WeakReference<Object> {
+
+ public MapReference(@Nonnull Object referent,
+ @Nonnull ReferenceQueue<Object> queue) {
+ super(checkNotNull(referent), checkNotNull(queue));
+ }
+ }
+}
Propchange:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/HybridMapFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactory.java?rev=1692079&r1=1692078&r2=1692079&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactory.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactory.java
Tue Jul 21 10:25:04 2015
@@ -36,19 +36,22 @@ import org.mapdb.Serializer;
public class MapDBMapFactory extends MapFactory {
private final AtomicInteger counter = new AtomicInteger();
- private final DB db;
+ private DB db;
- public MapDBMapFactory() {
- this.db = DBMaker.newTempFileDB()
- .deleteFilesAfterClose()
- .transactionDisable()
- .asyncWriteEnable()
- .make();
+ private synchronized DB getDB() {
+ if (db == null) {
+ this.db = DBMaker.newTempFileDB()
+ .deleteFilesAfterClose()
+ .transactionDisable()
+ .asyncWriteEnable()
+ .make();
+ }
+ return db;
}
@Override
public BTreeMap<String, Revision> create() {
- return db.createTreeMap(String.valueOf(counter.incrementAndGet()))
+ return getDB().createTreeMap(String.valueOf(counter.incrementAndGet()))
.valueSerializer(new RevisionSerializer())
.counterEnable()
.makeStringMap();
@@ -57,7 +60,7 @@ public class MapDBMapFactory extends Map
@Override
public synchronized BTreeMap<String, Revision> create(
Comparator<String> comparator) {
- return db.createTreeMap(String.valueOf(counter.incrementAndGet()))
+ return getDB().createTreeMap(String.valueOf(counter.incrementAndGet()))
.valueSerializer(new RevisionSerializer())
.keySerializer(new CustomKeySerializer(comparator))
.counterEnable()
@@ -65,8 +68,11 @@ public class MapDBMapFactory extends Map
}
@Override
- public void dispose() {
- db.close();
+ public synchronized void dispose() {
+ if (db != null) {
+ db.close();
+ db = null;
+ }
}
private static class CustomKeySerializer extends BTreeKeySerializer<String>
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapFactory.java?rev=1692079&r1=1692078&r2=1692079&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapFactory.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MapFactory.java
Tue Jul 21 10:25:04 2015
@@ -32,10 +32,15 @@ import org.apache.jackrabbit.oak.plugins
*/
public abstract class MapFactory {
- private static final boolean USE_MEMORY_MAP_FACTORY
- = Boolean.getBoolean("oak.useMemoryMapFactory");
+ private static boolean useMemoryMapFactory() {
+ return Boolean.getBoolean("oak.useMemoryMapFactory");
+ }
+
+ private static boolean useHybridMapFactory() {
+ return Boolean.getBoolean("oak.useHybridMapFactory");
+ }
- private static MapFactory DEFAULT = new MapFactory() {
+ public static final MapFactory DEFAULT = new MapFactory() {
@Override
public ConcurrentMap<String, Revision> create() {
return new ConcurrentHashMap<String, Revision>();
@@ -69,8 +74,10 @@ public abstract class MapFactory {
}
public static MapFactory createFactory() {
- if (USE_MEMORY_MAP_FACTORY) {
+ if (useMemoryMapFactory()) {
return MapFactory.getInstance();
+ } else if (useHybridMapFactory()) {
+ return new HybridMapFactory();
} else {
return new MapDBMapFactory();
}
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java?rev=1692079&r1=1692078&r2=1692079&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
Tue Jul 21 10:25:04 2015
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.plugin
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
@@ -28,11 +29,14 @@ import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.util.HybridMapFactory;
import org.apache.jackrabbit.oak.plugins.document.util.MapDBMapFactory;
import org.apache.jackrabbit.oak.plugins.document.util.MapFactory;
import org.junit.Ignore;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
public class UnsavedModificationsTest {
private static final String CHARS = "abcdefghijklmnopqrstuvwxyz";
@@ -123,7 +127,7 @@ public class UnsavedModificationsTest {
}
// OAK-3112
- @Ignore
+ @Ignore("Long running performance test")
@Test
public void performance() throws Exception {
DocumentStore store = new MemoryDocumentStore() {
@@ -137,8 +141,7 @@ public class UnsavedModificationsTest {
final DocumentNodeStore ns = new
DocumentMK.Builder().setDocumentStore(store)
.getNodeStore();
- // MapFactory factory = MapFactory.getInstance();
- MapFactory factory = new MapDBMapFactory();
+ MapFactory factory = new HybridMapFactory();
final UnsavedModifications pending = new UnsavedModifications(factory);
Thread t = new Thread(new Runnable() {
@@ -165,7 +168,7 @@ public class UnsavedModificationsTest {
}
paths.clear();
}
- if (num % 1000 == 0) {
+ if (random.nextFloat() < 0.00005) {
pending.persist(ns, new ReentrantLock());
}
}
@@ -189,6 +192,105 @@ public class UnsavedModificationsTest {
ns.dispose();
}
+ @Test
+ public void getPathsAfterPersist() throws Exception {
+ DocumentStore store = new MemoryDocumentStore() {
+ @Override
+ public <T extends Document> void update(Collection<T> collection,
+ List<String> keys,
+ UpdateOp updateOp) {
+ // ignore call
+ }
+ };
+ final DocumentNodeStore ns = new
DocumentMK.Builder().setDocumentStore(store)
+ .getNodeStore();
+
+ MapFactory factory = new HybridMapFactory();
+ UnsavedModifications pending = new UnsavedModifications(factory);
+
+ Revision r = new Revision(1, 0, 1);
+ for (int i = 0; i <= UnsavedModifications.IN_MEMORY_SIZE_LIMIT; i++) {
+ pending.put("/node-" + i, r);
+ }
+
+ // start iterating over paths
+ Iterator<String> paths = pending.getPaths().iterator();
+ for (int i = 0; i < 1000; i++) {
+ paths.next();
+ }
+
+ // drain pending, this will force it back to in-memory
+ pending.persist(ns, new ReentrantLock());
+
+ // loop over remaining paths
+ while (paths.hasNext()) {
+ paths.next();
+ }
+ pending.close();
+ }
+
+ @Test
+ public void getPathsWithRevisionAfterPersist() throws Exception {
+ DocumentStore store = new MemoryDocumentStore() {
+ @Override
+ public <T extends Document> void update(Collection<T> collection,
+ List<String> keys,
+ UpdateOp updateOp) {
+ // ignore call
+ }
+ };
+ final DocumentNodeStore ns = new
DocumentMK.Builder().setDocumentStore(store)
+ .getNodeStore();
+
+ MapFactory factory = new HybridMapFactory();
+ UnsavedModifications pending = new UnsavedModifications(factory);
+
+ Revision r = new Revision(1, 0, 1);
+ for (int i = 0; i <= UnsavedModifications.IN_MEMORY_SIZE_LIMIT; i++) {
+ pending.put("/node-" + i, r);
+ }
+
+ // start iterating over paths
+ Iterator<String> paths = pending.getPaths(r).iterator();
+ for (int i = 0; i < 1000; i++) {
+ paths.next();
+ }
+
+ // drain pending, this will force it back to in-memory
+ pending.persist(ns, new ReentrantLock());
+
+ // loop over remaining paths
+ while (paths.hasNext()) {
+ paths.next();
+ }
+ pending.close();
+ }
+
+ @Test
+ public void defaultMapFactoryCreate() {
+ MapFactory factory = MapFactory.createFactory();
+ assertEquals(MapDBMapFactory.class, factory.getClass());
+ factory.dispose();
+ }
+
+ @Test
+ public void useHybridMapFactory() {
+ System.setProperty("oak.useHybridMapFactory", "true");
+ MapFactory factory = MapFactory.createFactory();
+ assertEquals(HybridMapFactory.class, factory.getClass());
+ factory.dispose();
+ System.clearProperty("oak.useHybridMapFactory");
+ }
+
+ @Test
+ public void useMemoryMapFactory() {
+ System.setProperty("oak.useMemoryMapFactory", "true");
+ MapFactory factory = MapFactory.createFactory();
+ assertEquals(MapFactory.DEFAULT.getClass(), factory.getClass());
+ factory.dispose();
+ System.clearProperty("oak.useMemoryMapFactory");
+ }
+
private static String randomName(Random r, int len) {
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactoryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactoryTest.java?rev=1692079&r1=1692078&r2=1692079&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactoryTest.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/MapDBMapFactoryTest.java
Tue Jul 21 10:25:04 2015
@@ -16,12 +16,17 @@
*/
package org.apache.jackrabbit.oak.plugins.document.util;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.jackrabbit.oak.plugins.document.PathComparator;
import org.apache.jackrabbit.oak.plugins.document.Revision;
+import org.junit.After;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
import com.google.common.collect.Lists;
@@ -30,12 +35,32 @@ import static org.junit.Assert.assertEqu
/**
* <code>MapDBMapFactoryTest</code>...
*/
+@RunWith(Parameterized.class)
public class MapDBMapFactoryTest {
+ private MapFactory factory;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> factories() {
+ Object[][] factories = new Object[][] {
+ {new MapDBMapFactory()},
+ {new HybridMapFactory()},
+ {MapFactory.DEFAULT}
+ };
+ return Arrays.asList(factories);
+ }
+
+ public MapDBMapFactoryTest(MapFactory factory) {
+ this.factory = factory;
+ }
+
+ @After
+ public void dispose() {
+ factory.dispose();
+ }
+
@Test
public void comparator() {
- MapFactory factory = new MapDBMapFactory();
-
Revision r = new Revision(1, 0, 1);
Map<String, Revision> map = factory.create(PathComparator.INSTANCE);
@@ -58,7 +83,5 @@ public class MapDBMapFactoryTest {
List<String> actual = Lists.newArrayList(map.keySet());
assertEquals(expected, actual);
-
- factory.dispose();
}
}