Author: mreutegg Date: Tue Apr 8 14:11:01 2014 New Revision: 1585735 URL: http://svn.apache.org/r1585735 Log: OAK-1692: Document split may drop revisions
Merge fix from trunk. Modified: jackrabbit/oak/branches/1.0/ (props changed) jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java Propchange: jackrabbit/oak/branches/1.0/ ------------------------------------------------------------------------------ Merged /jackrabbit/oak/trunk:r1585719 Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1585735&r1=1585734&r2=1585735&view=diff ============================================================================== --- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java (original) +++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java Tue Apr 8 14:11:01 2014 @@ -42,6 +42,7 @@ import org.apache.jackrabbit.oak.plugins import org.apache.jackrabbit.oak.spi.state.AbstractChildNodeEntry; import org.apache.jackrabbit.oak.spi.state.AbstractNodeState; import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry; +import org.apache.jackrabbit.oak.spi.state.EqualsDiff; import org.apache.jackrabbit.oak.spi.state.NodeBuilder; import org.apache.jackrabbit.oak.spi.state.NodeState; import org.apache.jackrabbit.oak.spi.state.NodeStateDiff; @@ -110,7 +111,7 @@ class DocumentNodeState extends Abstract } else if (that instanceof ModifiedNodeState) { ModifiedNodeState modified = (ModifiedNodeState) that; if (modified.getBaseState() == this) { - return false; + return EqualsDiff.equals(this, modified); } } if (that instanceof NodeState) { Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1585735&r1=1585734&r2=1585735&view=diff ============================================================================== --- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original) +++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Tue Apr 8 14:11:01 2014 @@ -1413,9 +1413,11 @@ public final class DocumentNodeStore if (before != null) { NodeDocument after = store.find(Collection.NODES, op.getId()); if (after != null) { - LOG.info("Split operation on {}. Size before: {}, after: {}", + LOG.debug("Split operation on {}. Size before: {}, after: {}", id, before.getMemory(), after.getMemory()); } + } else { + LOG.debug("Split operation created {}", op.getId()); } } it.remove(); Modified: jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1585735&r1=1585734&r2=1585735&view=diff ============================================================================== --- jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java (original) +++ jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java Tue Apr 8 14:11:01 2014 @@ -958,9 +958,11 @@ public final class NodeDocument extends NodeDocument oldDoc = new NodeDocument(store); UpdateUtils.applyChanges(oldDoc, old, context.getRevisionComparator()); setSplitDocProps(this, oldDoc, old, high); - // only split if half of the data can be moved to old document + // only split if enough of the data can be moved to old document if (oldDoc.getMemory() > getMemory() * SPLIT_RATIO) { splitOps.add(old); + } else { + main = null; } } Modified: jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java?rev=1585735&r1=1585734&r2=1585735&view=diff ============================================================================== --- jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java (original) +++ jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentSplitTest.java Tue Apr 8 14:11:01 2014 @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.TreeSet; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; @@ -42,11 +43,17 @@ import com.google.common.collect.Sets; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; import static org.apache.jackrabbit.oak.plugins.document.MongoBlobGCTest.randomStream; +import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.NUM_REVS_THRESHOLD; +import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.PREV_SPLIT_FACTOR; +import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SPLIT_RATIO; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType; +import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation.Type.REMOVE_MAP_ENTRY; +import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation.Type.SET_MAP_ENTRY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * Check correct splitting of documents (OAK-926 & OAK-1342). @@ -479,6 +486,67 @@ public class DocumentSplitTest extends B } } + @Test + public void cascadingWithSplitRatio() { + String id = Utils.getIdFromPath("/test"); + mk.commit("/", "+\"test\":{}", null, null); + DocumentStore store = mk.getDocumentStore(); + int clusterId = mk.getNodeStore().getClusterId(); + + UpdateOp op = new UpdateOp(id, false); + // create some baggage + for (int i = 0; i < NUM_REVS_THRESHOLD / SPLIT_RATIO; i++) { + Revision r = Revision.newRevision(2); + op.setMapEntry("prop", r, "test value"); + NodeDocument.setRevision(op, r, "c"); + } + // these will be considered for a split + for (int i = 0; i < NUM_REVS_THRESHOLD; i++) { + Revision r = Revision.newRevision(clusterId); + op.setMapEntry("prop", r, "value"); + NodeDocument.setRevision(op, r, "c"); + } + // some fake previous doc references to trigger UpdateOp + // for an intermediate document + TreeSet<Revision> prev = Sets.newTreeSet(mk.getNodeStore().getRevisionComparator()); + for (int i = 0; i < PREV_SPLIT_FACTOR; i++) { + Revision low = Revision.newRevision(clusterId); + Revision high = Revision.newRevision(clusterId); + prev.add(high); + NodeDocument.setPrevious(op, new Range(high, low, 0)); + } + store.findAndUpdate(NODES, op); + + NodeDocument doc = store.find(NODES, id); + assertNotNull(doc); + List<UpdateOp> splitOps = Lists.newArrayList(doc.split(mk.getNodeStore())); + assertEquals(2, splitOps.size()); + // first update op is for the new intermediate doc + op = splitOps.get(0); + String newPrevId = Utils.getPreviousIdFor("/test", prev.last(), 1); + assertEquals(newPrevId, op.getId()); + // second update op is for the main document + op = splitOps.get(1); + assertEquals(id, op.getId()); + for (Map.Entry<UpdateOp.Key, UpdateOp.Operation> entry : op.getChanges().entrySet()) { + Revision r = entry.getKey().getRevision(); + assertNotNull(r); + assertEquals(clusterId, r.getClusterId()); + if (entry.getKey().getName().equals("_prev")) { + if (entry.getValue().type == REMOVE_MAP_ENTRY) { + assertTrue(prev.contains(r)); + } else if (entry.getValue().type == SET_MAP_ENTRY) { + assertEquals(newPrevId, Utils.getPreviousIdFor("/test", r, 1)); + } else { + fail("unexpected update operation " + entry); + } + } else { + fail("unexpected update operation " + entry); + } + } + + } + private void syncMKs(List<DocumentMK> mks, int idx) { mks.get(idx).runBackgroundOperations(); for (int i = 0; i < mks.size(); i++) {