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 to...@apache.org on 2018/10/02 11:02:44 UTC

svn commit: r1842610 - in /jackrabbit/oak/trunk: oak-it/src/test/java/org/apache/jackrabbit/oak/composite/ oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/ oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/

Author: tomekr
Date: Tue Oct  2 11:02:44 2018
New Revision: 1842610

URL: http://svn.apache.org/viewvc?rev=1842610&view=rev
Log:
OAK-7796: Remove the support for the writeable partial stores

Modified:
    jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreTest.java
    jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java
    jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java
    jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java
    jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositionContext.java
    jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/package-info.java
    jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeChildrenCountTest.java
    jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeCompareTest.java

Modified: jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreTest.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreTest.java Tue Oct  2 11:02:44 2018
@@ -59,7 +59,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDataSourceFactory;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBOptions;
-import org.apache.jackrabbit.oak.plugins.document.util.CountingDiff;
 import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
 import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
@@ -121,9 +120,9 @@ public class CompositeNodeStoreTest {
     @Before
     public void initStore() throws Exception {
         mip = Mounts.newBuilder()
-                .mount("temp", "/tmp")
-                .mount("deep", "/libs/mount")
-                .mount("empty", "/nowhere")
+                .readOnlyMount("temp", "/tmp")
+                .readOnlyMount("deep", "/libs/mount")
+                .readOnlyMount("empty", "/nowhere")
                 .readOnlyMount("readOnly", "/readOnly")
                 .build();
 
@@ -272,19 +271,7 @@ public class CompositeNodeStoreTest {
         globalBuilder.child("new");
         globalStore.merge(globalBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
 
-        // create a new child /tmp/new in the mounted store
-        NodeBuilder mountedBuilder = mountedStore.getRoot().builder();
-        mountedBuilder.getChildNode("tmp").child("new");
-        mountedStore.merge(mountedBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        // create a new child /libs/mount/new in the deeply mounted store
-        NodeBuilder deepMountBuilder = deepMountedStore.getRoot().builder();
-        deepMountBuilder.getChildNode("libs").getChildNode("mount").child("new");
-        deepMountedStore.merge(deepMountBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
         assertFalse("store incorrectly exposes child at /new", store.retrieve(checkpoint).hasChildNode("new"));
-        assertFalse("store incorrectly exposes child at /tmp/new", store.retrieve(checkpoint).getChildNode("tmp").hasChildNode("new"));
-        assertFalse("store incorrectly exposes child at /libs/mount/new", store.retrieve(checkpoint).getChildNode("libs").getChildNode("mount").hasChildNode("new"));
     }
 
     @Test
@@ -374,19 +361,6 @@ public class CompositeNodeStoreTest {
     }
 
     @Test
-    public void createNodeInMountedStore() throws Exception {
-
-        NodeBuilder builder = store.getRoot().builder();
-
-        builder.getChildNode("tmp").child("newNode");
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertTrue("Node must be added to composite store", store.getRoot().getChildNode("tmp").hasChildNode("newNode"));
-        assertTrue("Node must be added to owning (mounted) store", mountedStore.getRoot().getChildNode("tmp").hasChildNode("newNode"));
-    }
-
-    @Test
     public void removeNodeInRootStore() throws Exception {
         NodeBuilder builder = store.getRoot().builder();
 
@@ -398,27 +372,6 @@ public class CompositeNodeStoreTest {
         assertFalse("Node must be removed from the owning (root) store", globalStore.getRoot().hasChildNode("apps"));
     }
 
-
-    @Test
-    public void removeNodeInMountedStore() throws Exception {
-        NodeBuilder builder = store.getRoot().builder();
-
-        builder.getChildNode("tmp").child("newNode");
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertTrue("Node must be added to composite store", store.getRoot().getChildNode("tmp").hasChildNode("newNode"));
-
-        builder = store.getRoot().builder();
-
-        builder.getChildNode("tmp").getChildNode("newNode").remove();
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertFalse("Node must be removed from the composite store", store.getRoot().getChildNode("tmp").hasChildNode("newNode"));
-        assertFalse("Node must be removed from the owning (composite) store", globalStore.getRoot().getChildNode("tmp").hasChildNode("newNode"));
-    }
-
     @Test
     public void builderChildrenCountInRootStore() throws Exception {
         assertThat("root(childCount)", store.getRoot().builder().getChildNodeCount(100), equalTo(4l));
@@ -481,20 +434,6 @@ public class CompositeNodeStoreTest {
         assertThat("Node apps must not have any properties", store.getRoot().getChildNode("apps").getPropertyCount(), equalTo(0l));
     }
 
-
-    @Test
-    public void setChildNodeInMountStore() throws Exception {
-        NodeBuilder builder = store.getRoot().builder();
-
-        builder.getChildNode("tmp").setChildNode("child1");
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertTrue("Node child1 must still exist", store.getRoot().getChildNode("tmp").hasChildNode("child1"));
-        assertThat("Node child1 must not have any properties", store.getRoot().getChildNode("tmp").getChildNode("child1").getPropertyCount(), equalTo(0l));
-    }
-
-
     @Test
     public void builderBasedOnRootStoreChildNode() throws Exception {
         NodeBuilder builder = store.getRoot().builder();
@@ -513,24 +452,6 @@ public class CompositeNodeStoreTest {
     }
 
     @Test
-    public void builderBasedOnMountStoreChildNode() throws Exception {
-        NodeBuilder builder = store.getRoot().builder();
-        NodeBuilder tmpBuilder = builder.getChildNode("tmp");
-
-        tmpBuilder.removeProperty("prop1");
-        tmpBuilder.setChildNode("child3");
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertFalse("Node tmp must have no properties (composite store)", store.getRoot().getChildNode("tmp").hasProperty("prop1"));
-        assertFalse("Node tmp must have no properties (mounted store)", mountedStore.getRoot().getChildNode("tmp").hasProperty("prop1"));
-
-        assertTrue("Node /tmp/build3 must exist (composite store)", store.getRoot().getChildNode("tmp").hasChildNode("child3"));
-        assertTrue("Node /tmp/child3 must exist (mounted store)", mountedStore.getRoot().getChildNode("tmp").hasChildNode("child3"));
-
-    }
-
-    @Test
     public void freshBuilderForGlobalStore() {
         NodeBuilder builder = store.getRoot().builder();
 
@@ -657,17 +578,6 @@ public class CompositeNodeStoreTest {
     }
 
     @Test
-    public void resetOnMountedStore() {
-        NodeBuilder rootBuilder = store.getRoot().builder();
-        NodeBuilder builder = rootBuilder.getChildNode("tmp");
-        builder.child("newChild");
-
-        store.reset(rootBuilder);
-
-        assertFalse("Newly added child should no longer be visible after reset", builder.getChildNode("tmp").hasChildNode("newChild"));
-    }
-
-    @Test
     public void oldNodeStateDoesNotRefreshOnGlobalStore() throws Exception {
         NodeState old = store.getRoot();
 
@@ -681,21 +591,6 @@ public class CompositeNodeStoreTest {
         assertFalse("old NodeState should not see newly added child node after merge ", old.hasChildNode("newNode"));
     }
 
-    @Test
-    public void oldNodeStateDoesNotRefreshOnMountedStore() throws Exception {
-        NodeState old = store.getRoot();
-
-        NodeBuilder builder = store.getRoot().builder();
-
-        builder.getChildNode("tmp").child("newNode");
-
-        assertFalse("old NodeState should not see newly added child node before merge ", old.getChildNode("tmp").hasChildNode("newNode"));
-
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        assertFalse("old NodeState should not see newly added child node after merge ", old.getChildNode("tmp").hasChildNode("newNode"));
-    }
-
     // this test ensures that when going from State -> Builder -> State -> Builder the state is properly maintained
     @Test
     public void nestedBuilderFromState() throws Exception {
@@ -741,20 +636,8 @@ public class CompositeNodeStoreTest {
         globalBuilder.child("new");
         globalStore.merge(globalBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
 
-        // create a new child /tmp/new in the mounted store
-        NodeBuilder mountedBuilder = mountedStore.getRoot().builder();
-        mountedBuilder.getChildNode("tmp").child("new");
-        mountedStore.merge(mountedBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        // create a new child /libs/mount/new in the deeply mounted store
-        NodeBuilder deepMountBuilder = deepMountedStore.getRoot().builder();
-        deepMountBuilder.getChildNode("libs").getChildNode("mount").child("new");
-        deepMountedStore.merge(deepMountBuilder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
         NodeBuilder rootCheckpointBuilder = store.retrieve(checkpoint).builder();
         assertFalse("store incorrectly exposes child at /new", rootCheckpointBuilder.hasChildNode("new"));
-        assertFalse("store incorrectly exposes child at /tmp/new", rootCheckpointBuilder.getChildNode("tmp").hasChildNode("new"));
-        assertFalse("store incorrectly exposes child at /libs/mount/new", rootCheckpointBuilder.getChildNode("libs").getChildNode("mount").hasChildNode("new"));
     }
 
     @Test

Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java Tue Oct  2 11:02:44 2018
@@ -49,14 +49,9 @@ class CommitHookEnhancer implements Comm
         Map<MountedNodeStore, NodeState> beforeStates = newHashMap();
         Map<MountedNodeStore, NodeState> afterStates = newHashMap();
         for (MountedNodeStore mns : ctx.getNonDefaultStores()) {
-            if (mns.getMount().isReadOnly()) {
-                NodeState root = mns.getNodeStore().getRoot();
-                afterStates.put(mns, root);
-                beforeStates.put(mns, root);
-            } else {
-                afterStates.put(mns, mns.getNodeStore().rebase(builder.getNodeBuilder(mns)));
-                beforeStates.put(mns, builder.getNodeBuilder(mns).getBaseState());
-            }
+            NodeState root = mns.getNodeStore().getRoot();
+            afterStates.put(mns, root);
+            beforeStates.put(mns, root);
         }
         afterStates.put(ctx.getGlobalStore(), after);
         beforeStates.put(ctx.getGlobalStore(), before);

Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java Tue Oct  2 11:02:44 2018
@@ -29,7 +29,6 @@ import org.apache.jackrabbit.oak.composi
 import org.apache.jackrabbit.oak.spi.commit.ChangeDispatcher;
 import org.apache.jackrabbit.oak.spi.commit.CommitHook;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
-import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.commit.Observable;
 import org.apache.jackrabbit.oak.spi.commit.Observer;
 import org.apache.jackrabbit.oak.spi.mount.Mount;
@@ -37,7 +36,6 @@ import org.apache.jackrabbit.oak.spi.mou
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
-import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,9 +47,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,11 +59,7 @@ import static com.google.common.collect.
 import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Maps.filterKeys;
 import static com.google.common.collect.Maps.newHashMap;
-import static com.google.common.collect.Sets.difference;
-import static com.google.common.collect.Sets.filter;
-import static com.google.common.collect.Sets.newHashSet;
 import static java.lang.System.currentTimeMillis;
-import static org.apache.jackrabbit.oak.commons.PathUtils.isAncestor;
 import static org.apache.jackrabbit.oak.composite.ModifiedPathDiff.getModifiedPaths;
 
 /**
@@ -98,42 +92,48 @@ public class CompositeNodeStore implemen
 
     private static final String CHECKPOINT_METADATA_MOUNT = CHECKPOINT_METADATA + "mount.";
 
-    private final TreeSet<String> ignoreReadOnlyWritePaths;
-
     final CompositionContext ctx;
 
     private final ChangeDispatcher dispatcher;
 
-    private final Lock mergeLock;
+    private final Lock mergeLock = new ReentrantLock();
 
     // visible for testing only
     CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore, List<MountedNodeStore> nonDefaultStore) {
-        this(mip, globalStore, nonDefaultStore, Collections.<String>emptyList(), CompositeNodeStoreMonitor.EMPTY_INSTANCE, CompositeNodeStoreMonitor.EMPTY_INSTANCE);
+        this(mip, globalStore, nonDefaultStore, CompositeNodeStoreMonitor.EMPTY_INSTANCE, CompositeNodeStoreMonitor.EMPTY_INSTANCE);
     }
 
-    CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore, List<MountedNodeStore> nonDefaultStore, List<String> ignoreReadOnlyWritePaths, CompositeNodeStoreMonitor nodeStateMonitor, CompositeNodeStoreMonitor nodeBuilderMonitor) {
+    CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore, List<MountedNodeStore> nonDefaultStore, CompositeNodeStoreMonitor nodeStateMonitor, CompositeNodeStoreMonitor nodeBuilderMonitor) {
+        assertPartialMountsAreReadOnly(nonDefaultStore);
+
         this.ctx = new CompositionContext(mip, globalStore, nonDefaultStore, nodeStateMonitor, nodeBuilderMonitor);
-        this.ignoreReadOnlyWritePaths = new TreeSet<>(ignoreReadOnlyWritePaths);
-        this.mergeLock = new ReentrantLock();
         this.dispatcher = new ChangeDispatcher(getRoot());
 
         // setup observation proxy mechanism for underlying store for events not dispatched from within our
         // merge
         if (globalStore instanceof Observable) {
             Observable globalStoreObservable = (Observable) globalStore;
-            globalStoreObservable.addObserver(new MountedNodeStoreObserver());
+            globalStoreObservable.addObserver((root, info) -> dispatcher.contentChanged(ctx.createRootNodeState(root), info));
         }
     }
 
+    private static void assertPartialMountsAreReadOnly(List<MountedNodeStore> nonDefaultStores) {
+        List<String> readWriteMountNames = nonDefaultStores
+                .stream()
+                .map(MountedNodeStore::getMount)
+                .filter(m -> !m.isReadOnly())
+                .map(Mount::getName)
+                .collect(Collectors.toList());
+
+        checkArgument(readWriteMountNames.isEmpty(),
+                "Following partial mounts are write-enabled: ", readWriteMountNames);
+    }
+
     @Override
     public NodeState getRoot() {
         // the composite root state exposes the node states as they are
         // at this certain point in time, so we eagerly retrieve them from all stores
-        Map<MountedNodeStore, NodeState> nodeStates = newHashMap();
-        for (MountedNodeStore nodeStore : ctx.getAllMountedNodeStores()) {
-            nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
-        }
-        return ctx.createRootNodeState(nodeStates);
+        return ctx.createRootNodeState(ctx.getGlobalStore().getNodeStore().getRoot());
     }
 
     @Override
@@ -149,44 +149,22 @@ public class CompositeNodeStore implemen
         mergeLock.lock();
         try {
             // merge the global builder and apply the commit hooks within
-            Map<MountedNodeStore, NodeState> resultStates = newHashMap();
             MountedNodeStore globalStore = ctx.getGlobalStore();
             CommitHookEnhancer hookEnhancer = new CommitHookEnhancer(commitHook, ctx, nodeBuilder);
             NodeState globalResult = globalStore.getNodeStore().merge(nodeBuilder.getNodeBuilder(globalStore), hookEnhancer, info);
-            resultStates.put(globalStore, globalResult);
-
             if (!hookEnhancer.getUpdatedBuilder().isPresent()) {
                 // it means that the commit hook wasn't invoked, because there were
                 // no changes on the global store. we should invoke it anyway.
                 hookEnhancer.processCommit(globalResult, globalResult, info);
             }
-            CompositeNodeBuilder updatedBuilder = hookEnhancer.getUpdatedBuilder().get();
-
-            // merge the partial builders
-            for (MountedNodeStore mns : ctx.getNonDefaultStores()) {
-                NodeBuilder partialBuilder = updatedBuilder.getNodeBuilder(mns);
-
-                if (mns.getMount().isReadOnly()) {
-                    assertNoChange(mns, partialBuilder);
-                    resultStates.put(mns, mns.getNodeStore().getRoot());
-                } else {
-                    NodeState partialState = mns.getNodeStore().merge(partialBuilder, EmptyHook.INSTANCE, info);
-                    resultStates.put(mns, partialState);
-                }
-            }
-
-            CompositeNodeState newRoot = ctx.createRootNodeState(resultStates);
-            return newRoot;
+            return ctx.createRootNodeState(globalResult);
         } finally {
             mergeLock.unlock();
         }
    }
 
     private void assertNoChangesOnReadOnlyMounts(CompositeNodeBuilder nodeBuilder) throws CommitFailedException {
-        for (MountedNodeStore mountedNodeStore : ctx.getAllMountedNodeStores()) {
-            if (!mountedNodeStore.getMount().isReadOnly()) {
-                continue;
-            }
+        for (MountedNodeStore mountedNodeStore : ctx.getNonDefaultStores()) {
             NodeBuilder partialBuilder = nodeBuilder.getNodeBuilder(mountedNodeStore);
             assertNoChange(mountedNodeStore, partialBuilder);
         }
@@ -197,13 +175,8 @@ public class CompositeNodeStore implemen
         NodeState nodeState = partialBuilder.getNodeState();
         if (!nodeState.equals(baseState)) {
             Set<String> changedPaths = getModifiedPaths(baseState, nodeState);
-            Set<String> ignoredChangedPaths = getIgnoredPaths(changedPaths);
-            if (!ignoredChangedPaths.isEmpty()) {
-                LOG.debug("Can't merge following read-only paths (they are configured to be ignored): {}.", ignoredChangedPaths);
-            }
-            Set<String> failingChangedPaths = difference(changedPaths, ignoredChangedPaths);
-            if (!failingChangedPaths.isEmpty()) {
-                throw new CommitFailedException("CompositeStore", 31, "Unable to perform changes on read-only mount " + mountedNodeStore.getMount().getName() + ". Failing paths: " + failingChangedPaths.toString());
+            if (!changedPaths.isEmpty()) {
+                throw new CommitFailedException("CompositeStore", 31, "Unable to perform changes on read-only mount " + mountedNodeStore.getMount().getName() + ". Failing paths: " + changedPaths.toString());
             }
         }
     }
@@ -211,41 +184,19 @@ public class CompositeNodeStore implemen
     @Override
     public NodeState rebase(NodeBuilder builder) {
         checkArgument(builder instanceof CompositeNodeBuilder);
-
         CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
-        Map<MountedNodeStore, NodeState> resultStates = newHashMap();
-        for (MountedNodeStore mountedNodeStore : ctx.getAllMountedNodeStores()) {
-            NodeStore nodeStore = mountedNodeStore.getNodeStore();
-            NodeState result;
-            if (mountedNodeStore.getMount().isReadOnly()) {
-                result = nodeStore.getRoot();
-            } else {
-                NodeBuilder partialBuilder = nodeBuilder.getNodeBuilder(mountedNodeStore);
-                result = nodeStore.rebase(partialBuilder);
-            }
-            resultStates.put(mountedNodeStore, result);
-        }
-        return ctx.createRootNodeState(resultStates);
+        MountedNodeStore globalStore = ctx.getGlobalStore();
+        NodeState globalResult = globalStore.getNodeStore().rebase(nodeBuilder.getNodeBuilder(globalStore));
+        return ctx.createRootNodeState(globalResult);
     }
 
     @Override
     public NodeState reset(NodeBuilder builder) {
         checkArgument(builder instanceof CompositeNodeBuilder);
-
         CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
-        Map<MountedNodeStore, NodeState> resultStates = newHashMap();
-        for (MountedNodeStore mountedNodeStore : ctx.getAllMountedNodeStores()) {
-            NodeStore nodeStore = mountedNodeStore.getNodeStore();
-            NodeState result;
-            if (mountedNodeStore.getMount().isReadOnly()) {
-                result = nodeStore.getRoot();
-            } else {
-                NodeBuilder partialBuilder = nodeBuilder.getNodeBuilder(mountedNodeStore);
-                result = nodeStore.reset(partialBuilder);
-            }
-            resultStates.put(mountedNodeStore, result);
-        }
-        return ctx.createRootNodeState(resultStates);
+        MountedNodeStore globalStore = ctx.getGlobalStore();
+        NodeState globalResult = globalStore.getNodeStore().reset(nodeBuilder.getNodeBuilder(globalStore));
+        return ctx.createRootNodeState(globalResult);
     }
 
     @Override
@@ -288,13 +239,6 @@ public class CompositeNodeStore implemen
         Map<String, String> globalProperties = newHashMap(properties);
         globalProperties.put(CHECKPOINT_METADATA + "created", Long.toString(currentTimeMillis()));
         globalProperties.put(CHECKPOINT_METADATA + "expires", Long.toString(currentTimeMillis() + lifetime));
-        for (MountedNodeStore mns : ctx.getNonDefaultStores()) {
-            if (mns.getMount().isReadOnly()) {
-                continue;
-            }
-            String checkpoint = mns.getNodeStore().checkpoint(lifetime, properties);
-            globalProperties.put(CHECKPOINT_METADATA_MOUNT + mns.getMount().getName(), checkpoint);
-        }
         String newCheckpoint = ctx.getGlobalStore().getNodeStore().checkpoint(lifetime, globalProperties);
         if (LOG.isDebugEnabled()) {
             LOG.debug("Created checkpoint {}. Debug info:\n{}", newCheckpoint, checkpointDebugInfo());
@@ -335,11 +279,11 @@ public class CompositeNodeStore implemen
         Map<MountedNodeStore, NodeState> nodeStates = newHashMap();
         nodeStates.put(ctx.getGlobalStore(), ctx.getGlobalStore().getNodeStore().retrieve(checkpoint));
         for (MountedNodeStore nodeStore : ctx.getNonDefaultStores()) {
-            NodeState nodeState = null;
+            NodeState nodeState;
             String partialCheckpoint = getPartialCheckpointName(nodeStore, checkpoint, props, true);
-            if (partialCheckpoint == null && nodeStore.getMount().isReadOnly()) {
+            if (partialCheckpoint == null) {
                 nodeState = nodeStore.getNodeStore().getRoot();
-            } else if (partialCheckpoint != null) {
+            } else {
                 nodeState = nodeStore.getNodeStore().retrieve(partialCheckpoint);
             }
             nodeStates.put(nodeStore, nodeState);
@@ -362,17 +306,6 @@ public class CompositeNodeStore implemen
             props = Collections.emptyMap();
             result = true;
         }
-        for (MountedNodeStore nodeStore : ctx.getNonDefaultStores()) {
-            if (nodeStore.getMount().isReadOnly()) {
-                continue;
-            }
-            boolean released = false;
-            String partialCheckpoint = getPartialCheckpointName(nodeStore, checkpoint, props, false);
-            if (partialCheckpoint != null) {
-                released = nodeStore.getNodeStore().release(partialCheckpoint);
-            }
-            result &= released;
-        }
         if (LOG.isDebugEnabled()) {
             LOG.debug("Released checkpoint {}. Result: {}. Debug info:\n{}", checkpoint, result, checkpointDebugInfo());
         }
@@ -449,16 +382,6 @@ public class CompositeNodeStore implemen
         return dispatcher.addObserver(observer);
     }
 
-    private Set<String> getIgnoredPaths(Set<String> paths) {
-        return newHashSet(filter(paths, new Predicate<String>() {
-            @Override
-            public boolean apply(String path) {
-                String previousPath = ignoreReadOnlyWritePaths.floor(path);
-                return previousPath != null && (previousPath.equals(path) || isAncestor(previousPath, path));
-            }
-        }));
-    }
-
     public static class Builder {
 
         private final MountInfoProvider mip;
@@ -467,14 +390,10 @@ public class CompositeNodeStore implemen
 
         private final List<MountedNodeStore> nonDefaultStores = Lists.newArrayList();
 
-        private final List<String> ignoreReadOnlyWritePaths = Lists.newArrayList();
-
         private CompositeNodeStoreMonitor nodeStateMonitor = CompositeNodeStoreMonitor.EMPTY_INSTANCE;
 
         private CompositeNodeStoreMonitor nodeBuilderMonitor = CompositeNodeStoreMonitor.EMPTY_INSTANCE;
 
-        private boolean partialReadOnly = true;
-
         private NodeStoreChecks checks;
 
         public Builder(MountInfoProvider mip, NodeStore globalStore) {
@@ -502,36 +421,12 @@ public class CompositeNodeStore implemen
             return this;
         }
 
-        public Builder addIgnoredReadOnlyWritePath(String path) {
-            ignoreReadOnlyWritePaths.add(path);
-            return this;
-        }
-
-        public Builder setPartialReadOnly(boolean partialReadOnly) {
-            this.partialReadOnly = partialReadOnly;
-            return this;
-        }
-
         public CompositeNodeStore build() {
             checkMountsAreConsistentWithMounts();
-            if (partialReadOnly) {
-                assertPartialMountsAreReadOnly();
-            }
-            if ( checks != null ) {
+            if (checks != null) {
                 nonDefaultStores.forEach( s -> checks.check(globalStore, s));
             }
-            return new CompositeNodeStore(mip, globalStore, nonDefaultStores, ignoreReadOnlyWritePaths, nodeStateMonitor, nodeBuilderMonitor);
-        }
-
-        public void assertPartialMountsAreReadOnly() {
-            List<String> readWriteMountNames = Lists.newArrayList();
-            for (Mount mount : mip.getNonDefaultMounts()) {
-                if (!mount.isReadOnly()) {
-                    readWriteMountNames.add(mount.getName());
-                }
-            }
-            checkArgument(readWriteMountNames.isEmpty(),
-                    "Following partial mounts are write-enabled: ", readWriteMountNames);
+            return new CompositeNodeStore(mip, globalStore, nonDefaultStores, nodeStateMonitor, nodeBuilderMonitor);
         }
 
         private void checkMountsAreConsistentWithMounts() {
@@ -542,16 +437,4 @@ public class CompositeNodeStore implemen
                     buildMountCount, mipMountCount);
         }
     }
-
-    private class MountedNodeStoreObserver implements Observer {
-        @Override
-        public void contentChanged(@NotNull NodeState root, @NotNull CommitInfo info) {
-            Map<MountedNodeStore, NodeState> nodeStates = newHashMap();
-            for (MountedNodeStore nodeStore : ctx.getNonDefaultStores()) {
-                nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
-            }
-            nodeStates.put(ctx.getGlobalStore(), root);
-            dispatcher.contentChanged(ctx.createRootNodeState(nodeStates), info);
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStoreService.java Tue Oct  2 11:02:44 2018
@@ -22,7 +22,6 @@ import org.apache.felix.scr.annotations.
 import org.apache.felix.scr.annotations.ConfigurationPolicy;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Property;
-import org.apache.felix.scr.annotations.PropertyUnbounded;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.ReferencePolicy;
@@ -79,24 +78,12 @@ public class CompositeNodeStoreService {
     @Reference
     private StatisticsProvider statisticsProvider = StatisticsProvider.NOOP;
 
-    @Property(label = "Ignore read only writes",
-            unbounded = PropertyUnbounded.ARRAY,
-            description = "Writes to these read-only paths won't fail the commit"
-    )
-    private static final String PROP_IGNORE_READ_ONLY_WRITES = "ignoreReadOnlyWrites";
-
     @Property(label = "Enable node store checks",
             description = "Whether the composite node store constraints should be checked before start",
             boolValue = true
     )
     private static final String ENABLE_CHECKS = "enableChecks";
 
-    @Property(label = "Read-only mounts",
-            description = "The partial stores should be configured as read-only",
-            boolValue = true
-    )
-    private static final String PROP_PARTIAL_READ_ONLY = "partialReadOnly";
-
     @Property(label = "Pre-populate seed mount",
             description = "Setting this parameter to a mount name will enable pre-populating the empty default store"
     )
@@ -118,10 +105,6 @@ public class CompositeNodeStoreService {
 
     private ObserverTracker observerTracker;
 
-    private String[] ignoreReadOnlyWritePaths;
-
-    private boolean partialReadOnly;
-
     private String seedMount;
 
     private boolean pathStats;
@@ -131,8 +114,6 @@ public class CompositeNodeStoreService {
     @Activate
     protected void activate(ComponentContext context, Map<String, ?> config) throws IOException, CommitFailedException {
         this.context = context;
-        ignoreReadOnlyWritePaths = PropertiesUtil.toStringArray(config.get(PROP_IGNORE_READ_ONLY_WRITES), new String[0]);
-        partialReadOnly = PropertiesUtil.toBoolean(config.get(PROP_PARTIAL_READ_ONLY), true);
         seedMount = PropertiesUtil.toString(config.get(PROP_SEED_MOUNT), null);
         pathStats = PropertiesUtil.toBoolean(config.get(PATH_STATS), false);
         enableChecks = PropertiesUtil.toBoolean(config.get(ENABLE_CHECKS), true);
@@ -180,10 +161,6 @@ public class CompositeNodeStoreService {
         if (enableChecks) {
             builder.with(checks);
         }
-        builder.setPartialReadOnly(partialReadOnly);
-        for (String p : ignoreReadOnlyWritePaths) {
-            builder.addIgnoredReadOnlyWritePath(p);
-        }
 
         for (NodeStoreWithProps ns : nodeStores) {
             if (isGlobalNodeStore(ns)) {

Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositionContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositionContext.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositionContext.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositionContext.java Tue Oct  2 11:02:44 2018
@@ -36,6 +36,7 @@ import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
 import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
 import static java.util.Collections.singletonList;
 
 class CompositionContext {
@@ -158,6 +159,15 @@ class CompositionContext {
         return getOwningStore(PathUtils.concat(parentPath, childName)) == mountedNodeStore;
     }
 
+    CompositeNodeState createRootNodeState(NodeState globalRootState) {
+        Map<MountedNodeStore, NodeState> nodeStates = newHashMap();
+        nodeStates.put(getGlobalStore(), globalRootState);
+        for (MountedNodeStore nodeStore : getNonDefaultStores()) {
+            nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
+        }
+        return createRootNodeState(nodeStates);
+    }
+
     CompositeNodeState createRootNodeState(Map<MountedNodeStore, NodeState> rootStates) {
         for (Map.Entry<MountedNodeStore, NodeState> e : rootStates.entrySet()) {
             MountedNodeStore mns = e.getKey();

Modified: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/package-info.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/package-info.java Tue Oct  2 11:02:44 2018
@@ -55,7 +55,7 @@
  *  This is obviously correct but may be slow.
  *  {@link org.apache.jackrabbit.oak.composite.CompositionContext#getContributingStores(java.lang.String, java.util.function.Function)}
  */
-@Version("0.3.0")
+@Version("1.0.0")
 package org.apache.jackrabbit.oak.composite;
 
 import org.osgi.annotation.versioning.Version;
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeChildrenCountTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeChildrenCountTest.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeChildrenCountTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeChildrenCountTest.java Tue Oct  2 11:02:44 2018
@@ -34,7 +34,6 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
-import org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.junit.Test;
@@ -70,7 +69,7 @@ public class CompositeChildrenCountTest
 
     @Test
     public void multipleContributingStores() {
-        MountInfoProvider mip = Mounts.newBuilder().mount("libs", "/libs", "/libs1", "/libs2", "/libs3", "/libs4").build();
+        MountInfoProvider mip = Mounts.newBuilder().readOnlyMount("libs", "/libs", "/libs1", "/libs2", "/libs3", "/libs4").build();
         NodeStore globalStore = new MemoryNodeStore();
         NodeStore libsStore = new MemoryNodeStore();
 
@@ -121,7 +120,7 @@ public class CompositeChildrenCountTest
 
     @Test
     public void contributingStoreReturnsInfinity() {
-        MountInfoProvider mip = Mounts.newBuilder().mount("libs", "/libs", "/libs1", "/libs2", "/libs3", "/libs4").build();
+        MountInfoProvider mip = Mounts.newBuilder().readOnlyMount("libs", "/libs", "/libs1", "/libs2", "/libs3", "/libs4").build();
         NodeStore globalStore = new MemoryNodeStore();
         NodeStore libsStore = new MemoryNodeStore();
 

Modified: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeCompareTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeCompareTest.java?rev=1842610&r1=1842609&r2=1842610&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeCompareTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CompositeCompareTest.java Tue Oct  2 11:02:44 2018
@@ -97,7 +97,7 @@ public class CompositeCompareTest {
 
     @Test
     public void onlyPropertiesOnMainNodesAreCompared() throws CommitFailedException {
-        MountInfoProvider mip = Mounts.newBuilder().mount("libs", "/libs").build();
+        MountInfoProvider mip = Mounts.newBuilder().readOnlyMount("libs", "/libs").build();
         NodeStore globalStore = new MemoryNodeStore();
         NodeStore libsStore = new MemoryNodeStore();
 
@@ -132,7 +132,7 @@ public class CompositeCompareTest {
 
     @Test
     public void nodesOutsideTheMountsAreIgnored() throws CommitFailedException {
-        MountInfoProvider mip = Mounts.newBuilder().mount("libs", "/libs").build();
+        MountInfoProvider mip = Mounts.newBuilder().readOnlyMount("libs", "/libs").build();
         NodeStore globalStore = new MemoryNodeStore();
         NodeStore libsStore = new MemoryNodeStore();