Author: tomekr
Date: Mon Jul 17 10:55:26 2017
New Revision: 1802126
URL: http://svn.apache.org/viewvc?rev=1802126&view=rev
Log:
OAK-6425: Make the CompositeNodeStore thread-safe
New, lock-less approach.
Added:
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/AtomicCompositeMergeTest.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java
Modified:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeBuilder.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeState.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/CompositionContext.java
Added:
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/AtomicCompositeMergeTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/AtomicCompositeMergeTest.java?rev=1802126&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/AtomicCompositeMergeTest.java
(added)
+++
jackrabbit/oak/trunk/oak-it/src/test/java/org/apache/jackrabbit/oak/composite/AtomicCompositeMergeTest.java
Mon Jul 17 10:55:26 2017
@@ -0,0 +1,213 @@
+/*
+ * 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.composite;
+
+import com.google.common.io.Closer;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.InitialContent;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.QueryEngine;
+import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.ResultRow;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.commons.IOUtils;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
+import
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.query.Query;
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.oak.api.QueryEngine.NO_MAPPINGS;
+import static org.junit.Assert.assertEquals;
+
+public class AtomicCompositeMergeTest {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(AtomicCompositeMergeTest.class);
+
+ private static final int THREADS = 6;
+
+ private static final String TEST_UUID = IdentifierManager.generateUUID();
+
+ private Closer closer;
+
+ @Before
+ public void initNodeStore() {
+ closer = Closer.create();
+ }
+
+ @After
+ public void closeAll() throws IOException {
+ closer.close();
+ }
+
+ @Test
+ @Ignore
+ public void testLocalMerges() throws InterruptedException, IOException,
ParseException, CommitFailedException {
+ Oak oak = getOak(getCompositeNodeStore(new MemoryNodeStore()));
+ testAtomicMerges(clusterId -> oak);
+ }
+
+ @Test
+ public void testDistributedMerge() throws InterruptedException,
IOException, ParseException, CommitFailedException {
+ MemoryDocumentStore sharedDocStore = new MemoryDocumentStore();
+ testAtomicMerges(clusterId -> {
+ DocumentNodeStore docNodeStore = new DocumentMK.Builder()
+ .setDocumentStore(sharedDocStore)
+ .setClusterId(clusterId)
+ .getNodeStore();
+ closer.register(() -> docNodeStore.dispose());
+ NodeStore compositeNodeStore = getCompositeNodeStore(docNodeStore);
+ return getOak(compositeNodeStore);
+ });
+ }
+
+ private void testAtomicMerges(Function<Integer, Oak> oakSupplier) throws
InterruptedException, IOException, ParseException, CommitFailedException {
+ Set<String> failedMerges = Collections.synchronizedSet(newHashSet());
+ List<Thread> threads = newArrayList();
+
+ ContentSession generalSession =
oakSupplier.apply(100).createContentSession();
+ closer.register(generalSession);
+ waitForReindexing(generalSession);
+ sleep(1000); // sleep for a sec, so the new repository have chance to
initialize itself
+
+ for (int i = 0; i < THREADS; i++) {
+ String name = "child_" + i;
+ Oak oak = oakSupplier.apply(i + 1);
+ ContentSession session = oak.createContentSession();
+ threads.add(new Thread(() -> {
+ LOG.info("Started thread {}", name);
+ try {
+ Root root = session.getLatestRoot();
+
root.getTree("/").addChild(name).setProperty(JcrConstants.JCR_UUID, TEST_UUID);
+ root.commit();
+ LOG.info("Merged successfully the node /{}: {}", name,
root.getTree("/" + name));
+ } catch (CommitFailedException e) {
+ LOG.info("Expected failure", e);
+ failedMerges.add(name);
+ } catch (Exception e) {
+ LOG.error("Can't commit", e);
+ } finally {
+ IOUtils.closeQuietly(session);
+ }
+ }));
+ }
+
+ threads.forEach(Thread::start);
+ threads.forEach(AtomicCompositeMergeTest::join);
+
+ List<String> uuidPaths = waitForUuid(generalSession, TEST_UUID);
+
+ assertEquals("There should be just one indexed value for the
TEST_UUID, but following are given: " + uuidPaths + ". Failed merge list: " +
failedMerges, 1, uuidPaths.size());
+ assertEquals("There should be " + (THREADS - 1) + " failed merges, but
following are given: " + failedMerges,THREADS - 1, failedMerges.size());
+ }
+
+ private static List<String> waitForUuid(ContentSession session, String
uuid) throws ParseException {
+ for (int i = 0; i < 20; i++) {
+ List<String> result = queryUuid(session, uuid);
+ if (result.isEmpty()) {
+ sleep(500);
+ } else {
+ return result;
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ private static List<String> queryUuid(ContentSession session, String uuid)
throws ParseException {
+ Map<String, PropertyValue> bindings = Collections.singletonMap("id",
PropertyValues.newString(uuid));
+ Result result = session.getLatestRoot().getQueryEngine().executeQuery(
+ "SELECT * FROM [nt:base] WHERE [jcr:uuid] = $id" +
QueryEngine.INTERNAL_SQL2_QUERY,
+ Query.JCR_SQL2,
+ bindings, NO_MAPPINGS);
+ return StreamSupport.stream(result.getRows().spliterator(), false)
+ .map(r -> r.getPath())
+ .collect(Collectors.toList());
+ }
+
+ private void waitForReindexing(ContentSession session) throws
CommitFailedException, ParseException {
+ String tmpUuid = IdentifierManager.generateUUID();
+
+ Root root = session.getLatestRoot();
+ root.getTree("/").addChild("tmp").setProperty(JcrConstants.JCR_UUID,
tmpUuid);
+ root.commit();
+
+ assertEquals(1, waitForUuid(session, tmpUuid).size());
+
+ root.getTree("/tmp").remove();
+ root.commit();
+ }
+
+ private static void join(Thread t) {
+ try {
+ t.join();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void sleep(long millis) {
+ if (millis <= 0) {
+ return;
+ }
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ LOG.error("Interrupted", e);
+ }
+ }
+
+ private static NodeStore getCompositeNodeStore(NodeStore globalNodeStore) {
+ return new CompositeNodeStore(Mounts.defaultMountInfoProvider(),
globalNodeStore, Collections.emptyList());
+ }
+
+ private static Oak getOak(NodeStore nodeStore) {
+ return new Oak(nodeStore)
+ .with(new OpenSecurityProvider())
+ .with(new PropertyIndexEditorProvider())
+ .with(new InitialContent());
+
+ }
+}
Added:
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=1802126&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java
(added)
+++
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CommitHookEnhancer.java
Mon Jul 17 10:55:26 2017
@@ -0,0 +1,77 @@
+/*
+ * 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.composite;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.CommitHook;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import javax.annotation.Nonnull;
+import java.util.Map;
+import java.util.Optional;
+
+import static com.google.common.collect.Maps.newHashMap;
+
+class CommitHookEnhancer implements CommitHook {
+
+ private final CompositionContext ctx;
+
+ private final Map<MountedNodeStore, NodeBuilder> builders;
+
+ private final CommitHook hook;
+
+ private Optional<CompositeNodeBuilder> updatedBuilder = Optional.empty();
+
+ CommitHookEnhancer(CommitHook hook, CompositionContext ctx,
Map<MountedNodeStore, NodeBuilder> builders) {
+ this.ctx = ctx;
+ this.builders = builders;
+ this.hook = hook;
+ }
+
+ @Nonnull
+ @Override
+ public NodeState processCommit(NodeState before, NodeState after,
CommitInfo info) throws CommitFailedException {
+ Map<MountedNodeStore, NodeState> beforeStates = newHashMap();
+ Map<MountedNodeStore, NodeState> afterStates = newHashMap();
+ for (Map.Entry<MountedNodeStore, NodeBuilder> e : builders.entrySet())
{
+ afterStates.put(e.getKey(),
e.getKey().getNodeStore().rebase(e.getValue()));
+ beforeStates.put(e.getKey(), e.getValue().getBaseState());
+ }
+ beforeStates.put(ctx.getGlobalStore(), before);
+ afterStates.put(ctx.getGlobalStore(), after);
+
+ CompositeNodeState compositeBefore =
ctx.createRootNodeState(beforeStates);
+ CompositeNodeState compositeAfter =
ctx.createRootNodeState(afterStates);
+
+ NodeState result = hook.processCommit(compositeBefore, compositeAfter,
info);
+ updatedBuilder = Optional.of(toComposite(result, compositeBefore));
+ return
updatedBuilder.get().getNodeState().getNodeStates().get(ctx.getGlobalStore());
+ }
+
+ Optional<CompositeNodeBuilder> getUpdatedBuilder() {
+ return updatedBuilder;
+ }
+
+ private CompositeNodeBuilder toComposite(NodeState nodeState,
CompositeNodeState compositeRoot) {
+ CompositeNodeBuilder builder = compositeRoot.builder();
+ nodeState.compareAgainstBaseState(compositeRoot, new
ApplyDiff(builder));
+ return builder;
+ }
+}
Modified:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeBuilder.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeBuilder.java?rev=1802126&r1=1802125&r2=1802126&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeBuilder.java
(original)
+++
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeBuilder.java
Mon Jul 17 10:55:26 2017
@@ -83,12 +83,12 @@ class CompositeNodeBuilder implements No
}
@Override
- public NodeState getNodeState() {
+ public CompositeNodeState getNodeState() {
return new CompositeNodeState(path, new
IdentityHashMap<>(buildersToNodeStates(nodeBuilders)), ctx);
}
@Override
- public NodeState getBaseState() {
+ public CompositeNodeState getBaseState() {
return new CompositeNodeState(path,
buildersToBaseStates(nodeBuilders), ctx);
}
Modified:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeState.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeState.java?rev=1802126&r1=1802125&r2=1802126&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeState.java
(original)
+++
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeState.java
Mon Jul 17 10:55:26 2017
@@ -75,6 +75,10 @@ class CompositeNodeState extends Abstrac
this.owningStore = ctx.getOwningStore(path);
}
+ Map<MountedNodeStore, NodeState> getNodeStates() {
+ return nodeStates;
+ }
+
@Override
public boolean exists() {
return getWrappedNodeState().exists();
@@ -198,7 +202,7 @@ class CompositeNodeState extends Abstrac
// write operations
@Override
- public NodeBuilder builder() {
+ public CompositeNodeBuilder builder() {
Map<MountedNodeStore, NodeBuilder> nodeBuilders =
transformValues(nodeStates, new Function<NodeState, NodeBuilder>() {
@Override
public NodeBuilder apply(NodeState input) {
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=1802126&r1=1802125&r2=1802126&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
Mon Jul 17 10:55:26 2017
@@ -32,7 +32,6 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.commit.Observer;
import org.apache.jackrabbit.oak.spi.mount.Mount;
import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
-import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -49,8 +48,8 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -103,7 +102,7 @@ public class CompositeNodeStore implemen
private final List<Observer> observers = new CopyOnWriteArrayList<>();
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock mergeLock;
// visible for testing only
CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore,
List<MountedNodeStore> nonDefaultStore) {
@@ -113,6 +112,7 @@ public class CompositeNodeStore implemen
CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore,
List<MountedNodeStore> nonDefaultStore, List<String> ignoreReadOnlyWritePaths) {
this.ctx = new CompositionContext(mip, globalStore, nonDefaultStore);
this.ignoreReadOnlyWritePaths = new
TreeSet<>(ignoreReadOnlyWritePaths);
+ this.mergeLock = new ReentrantLock();
}
@Override
@@ -120,15 +120,10 @@ public class CompositeNodeStore implemen
// 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();
- lock.readLock().lock();
- try {
- for (MountedNodeStore nodeStore : ctx.getAllMountedNodeStores()) {
- nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
- }
- } finally {
- lock.readLock().unlock();
+ for (MountedNodeStore nodeStore : ctx.getAllMountedNodeStores()) {
+ nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
}
- return createRootNodeState(nodeStates);
+ return ctx.createRootNodeState(nodeStates);
}
@Override
@@ -139,27 +134,33 @@ public class CompositeNodeStore implemen
throw new IllegalArgumentException();
}
+ assertNoChangesOnReadOnlyMounts(nodeBuilder);
+
+ // merge the global builder and apply the commit hooks within
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
- lock.writeLock().lock();
- try {
- // run commit hooks and apply the changes to the builder instance
- NodeState rebased = rebase(nodeBuilder);
- NodeState processed =
commitHook.processCommit(nodeBuilder.getBaseState(), rebased, info);
- processed.compareAgainstBaseState(rebased, new
ApplyDiff(nodeBuilder));
-
- assertNoChangesOnReadOnlyMounts(nodeBuilder);
-
- // apply the accumulated changes on individual NodeStore instances
- for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
- NodeStore nodeStore = mountedNodeStore.getNodeStore();
- NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
- NodeState result = nodeStore.merge(partialBuilder,
EmptyHook.INSTANCE, info);
- resultStates.put(mountedNodeStore, result);
+ MountedNodeStore globalStore = ctx.getGlobalStore();
+ CommitHookEnhancer hookEnhancer = new CommitHookEnhancer(commitHook,
ctx, nodeBuilder.getBuilders());
+ NodeState globalResult =
globalStore.getNodeStore().merge(nodeBuilder.getBuilders().get(globalStore),
hookEnhancer, info);
+ resultStates.put(globalStore, globalResult);
+ CompositeNodeBuilder updatedBuilder =
hookEnhancer.getUpdatedBuilder().orElse(nodeBuilder);
+
+ // merge the partial builders
+ for (MountedNodeStore mns : ctx.getNonDefaultStores()) {
+ NodeBuilder partialBuilder = updatedBuilder.getBuilders().get(mns);
+
+ if (mns.getMount().isReadOnly()) {
+ if
(!partialBuilder.getNodeState().equals(partialBuilder.getBaseState())) {
+ throw new CommitFailedException("CompositeStore", 31,
"Unable to perform changes on read-only mount " + mns.getMount().getName());
+ }
+ resultStates.put(mns, partialBuilder.getBaseState());
+ continue;
}
- } finally {
- lock.writeLock().unlock();
+
+ NodeState partialState = mns.getNodeStore().merge(partialBuilder,
EmptyHook.INSTANCE, info);
+ resultStates.put(mns, partialState);
}
- CompositeNodeState newRoot = createRootNodeState(resultStates);
+
+ CompositeNodeState newRoot = ctx.createRootNodeState(resultStates);
for (Observer observer : observers) {
observer.contentChanged(newRoot, info);
}
@@ -194,19 +195,13 @@ public class CompositeNodeStore implemen
CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
-
- lock.readLock().lock();
- try {
- for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
- NodeStore nodeStore = mountedNodeStore.getNodeStore();
- NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
- NodeState result = nodeStore.rebase(partialBuilder);
- resultStates.put(mountedNodeStore, result);
- }
- } finally {
- lock.readLock().unlock();
+ for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
+ NodeStore nodeStore = mountedNodeStore.getNodeStore();
+ NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
+ NodeState result = nodeStore.rebase(partialBuilder);
+ resultStates.put(mountedNodeStore, result);
}
- return createRootNodeState(resultStates);
+ return ctx.createRootNodeState(resultStates);
}
@Override
@@ -215,23 +210,13 @@ public class CompositeNodeStore implemen
CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
-
- lock.readLock().lock();
- try {
- for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
- NodeStore nodeStore = mountedNodeStore.getNodeStore();
- NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
- NodeState result = nodeStore.reset(partialBuilder);
- resultStates.put(mountedNodeStore, result);
- }
- } finally {
- lock.readLock().unlock();
+ for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
+ NodeStore nodeStore = mountedNodeStore.getNodeStore();
+ NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
+ NodeState result = nodeStore.reset(partialBuilder);
+ resultStates.put(mountedNodeStore, result);
}
- return createRootNodeState(resultStates);
- }
-
- private CompositeNodeState createRootNodeState(Map<MountedNodeStore,
NodeState> rootStates) {
- return new CompositeNodeState("/", rootStates, ctx);
+ return ctx.createRootNodeState(resultStates);
}
@Override
@@ -274,24 +259,18 @@ 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));
-
- lock.readLock().lock();
- try {
- 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());
+ for (MountedNodeStore mns : ctx.getNonDefaultStores()) {
+ if (mns.getMount().isReadOnly()) {
+ continue;
}
- return newCheckpoint;
- } finally {
- lock.readLock().unlock();
+ 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());
}
+ return newCheckpoint;
}
@Override
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=1802126&r1=1802125&r2=1802126&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
Mon Jul 17 10:55:26 2017
@@ -172,4 +172,14 @@ class CompositionContext {
}
};
}
+
+ CompositeNodeState createRootNodeState(Map<MountedNodeStore, NodeState>
rootStates) {
+ for (NodeState s : rootStates.values()) {
+ if (s instanceof CompositeNodeState) {
+ throw new IllegalArgumentException("Nesting composite node
states is not supported");
+ }
+ }
+ return new CompositeNodeState("/", rootStates, this);
+ }
+
}