Author: mreutegg
Date: Mon Sep 16 13:47:36 2013
New Revision: 1523648
URL: http://svn.apache.org/r1523648
Log:
OAK-926: MongoMK: split documents when they are too large
- Split regular property history as well
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java?rev=1523648&r1=1523647&r2=1523648&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java
Mon Sep 16 13:47:36 2013
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.oak.plugins.mongomk;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -116,6 +117,13 @@ public class NodeDocument extends Docume
*/
private static final String LAST_REV = "_lastRev";
+ /**
+ * Properties to ignore when a document is split.
+ */
+ private static final Set<String> IGNORE_ON_SPLIT =
+ Collections.unmodifiableSet(new HashSet<String>(
+ Arrays.asList(ID, MODIFIED, PREVIOUS, LAST_REV)));
+
final DocumentStore store;
/**
@@ -130,6 +138,27 @@ public class NodeDocument extends Docume
}
/**
+ * Gets the value map for the given key. This method is similar to {@link
+ * #get(String)} but only returns a map instance if the value associated
+ * with <code>key</code> is a map. The returned value map may span multiple
+ * documents if the values of the given <code>key</code> were split off to
+ * {@link #PREVIOUS} documents.
+ *
+ * @param key a string key.
+ * @return the map associated with the key or <code>null</code> if there is
+ * no such entry.
+ */
+ @CheckForNull
+ public Map<String, String> getValueMap(@Nonnull String key) {
+ Object value = super.get(key);
+ if (IGNORE_ON_SPLIT.contains(key) || !(value instanceof Map)) {
+ return null;
+ } else {
+ return ValueMap.create(this, key);
+ }
+ }
+
+ /**
* @return the system time this object was created.
*/
public final long getCreated() {
@@ -142,14 +171,11 @@ public class NodeDocument extends Docume
@Nonnull
public Map<Integer, Revision> getLastRev() {
Map<Integer, Revision> map = Maps.newHashMap();
- @SuppressWarnings("unchecked")
- Map<String, String> valueMap = (Map<String, String>) get(LAST_REV);
- if (valueMap != null) {
- for (Map.Entry<String, String> e : valueMap.entrySet()) {
- int clusterId = Integer.parseInt(e.getKey());
- Revision rev = Revision.fromString(e.getValue());
- map.put(clusterId, rev);
- }
+ Map<String, String> valueMap = getLocalMap(LAST_REV);
+ for (Map.Entry<String, String> e : valueMap.entrySet()) {
+ int clusterId = Integer.parseInt(e.getKey());
+ Revision rev = Revision.fromString(e.getValue());
+ map.put(clusterId, rev);
}
return map;
}
@@ -368,9 +394,7 @@ public class NodeDocument extends Docume
if (!Utils.isPropertyName(key)) {
continue;
}
- Object v = get(key);
- @SuppressWarnings("unchecked")
- Map<String, String> valueMap = (Map<String, String>) v;
+ Map<String, String> valueMap = getValueMap(key);
if (valueMap != null) {
if (valueMap instanceof NavigableMap) {
// TODO instanceof should be avoided
@@ -569,8 +593,7 @@ public class NodeDocument extends Docume
continue;
}
// was this property touched after baseRevision?
- @SuppressWarnings("unchecked")
- Map<String, Object> changes = (Map<String, Object>) get(name);
+ Map<String, String> changes = getValueMap(name);
if (changes == null) {
continue;
}
@@ -611,7 +634,10 @@ public class NodeDocument extends Docume
}
Map<String, NavigableMap<Revision, String>> splitValues
= new HashMap<String, NavigableMap<Revision, String>>();
- for (String property : new String[]{REVISIONS, COMMIT_ROOT, DELETED}) {
+ for (String property : data.keySet()) {
+ if (IGNORE_ON_SPLIT.contains(property)) {
+ continue;
+ }
NavigableMap<Revision, String> splitMap
= new TreeMap<Revision,
String>(context.getRevisionComparator());
splitValues.put(property, splitMap);
@@ -770,7 +796,7 @@ public class NodeDocument extends Docume
@Nonnull
Map<String, String> getLocalMap(String key) {
@SuppressWarnings("unchecked")
- Map<String, String> map = (Map<String, String>) get(key);
+ Map<String, String> map = (Map<String, String>) super.get(key);
if (map == null) {
map = Collections.emptyMap();
}
Modified:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java?rev=1523648&r1=1523647&r2=1523648&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java
Mon Sep 16 13:47:36 2013
@@ -128,4 +128,34 @@ public class DocumentSplitTest extends B
assertTrue(doc.isCommitted(rev));
}
}
+
+ @Test
+ public void splitPropertyRevisions() throws Exception {
+ DocumentStore store = mk.getDocumentStore();
+ mk.commit("/", "+\"foo\":{}", null, null);
+ NodeDocument doc = store.find(Collection.NODES,
Utils.getIdFromPath("/foo"));
+ assertNotNull(doc);
+ Set<String> revisions = Sets.newHashSet();
+ // create nodes
+ while (revisions.size() <= NodeDocument.REVISIONS_SPLIT_OFF_SIZE) {
+ revisions.add(mk.commit("/", "^\"foo/prop\":" + revisions.size(),
null, null));
+ }
+ mk.runBackgroundOperations();
+ doc = store.find(Collection.NODES, Utils.getIdFromPath("/foo"));
+ assertNotNull(doc);
+ Map<String, String> localRevs = doc.getLocalRevisions();
+ // one remaining in the local revisions map
+ assertEquals(1, localRevs.size());
+ for (String r : revisions) {
+ Revision rev = Revision.fromString(r);
+ assertTrue(doc.isCommitted(rev));
+ }
+ // all revisions in the prop map
+ Map<String, String> valueMap = doc.getValueMap("prop");
+ assertNotNull(valueMap);
+ assertEquals((long) revisions.size(), valueMap.size());
+ // one remaining revision in the local map
+ valueMap = doc.getLocalMap("prop");
+ assertEquals(1L, valueMap.size());
+ }
}