Author: tomekr
Date: Wed Jul 5 19:08:26 2017
New Revision: 1800914
URL: http://svn.apache.org/viewvc?rev=1800914&view=rev
Log:
OAK-6425: Make the CompositeNodeStore thread-safe
Modified:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CompositeNodeStore.java
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=1800914&r1=1800913&r2=1800914&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
Wed Jul 5 19:08:26 2017
@@ -49,6 +49,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 static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -101,6 +103,8 @@ public class CompositeNodeStore implemen
private final List<Observer> observers = new CopyOnWriteArrayList<>();
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
// visible for testing only
CompositeNodeStore(MountInfoProvider mip, NodeStore globalStore,
List<MountedNodeStore> nonDefaultStore) {
this(mip, globalStore, nonDefaultStore,
Collections.<String>emptyList());
@@ -116,8 +120,13 @@ 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();
- for (MountedNodeStore nodeStore : ctx.getAllMountedNodeStores()) {
- nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
+ lock.readLock().lock();
+ try {
+ for (MountedNodeStore nodeStore : ctx.getAllMountedNodeStores()) {
+ nodeStates.put(nodeStore, nodeStore.getNodeStore().getRoot());
+ }
+ } finally {
+ lock.readLock().unlock();
}
return createRootNodeState(nodeStates);
}
@@ -130,20 +139,25 @@ public class CompositeNodeStore implemen
throw new IllegalArgumentException();
}
- // 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
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
- 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);
+ 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);
+ }
+ } finally {
+ lock.writeLock().unlock();
}
CompositeNodeState newRoot = createRootNodeState(resultStates);
for (Observer observer : observers) {
@@ -180,11 +194,17 @@ public class CompositeNodeStore implemen
CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
- for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
- NodeStore nodeStore = mountedNodeStore.getNodeStore();
- NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
- NodeState result = nodeStore.rebase(partialBuilder);
- resultStates.put(mountedNodeStore, result);
+
+ 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();
}
return createRootNodeState(resultStates);
}
@@ -195,11 +215,17 @@ public class CompositeNodeStore implemen
CompositeNodeBuilder nodeBuilder = (CompositeNodeBuilder) builder;
Map<MountedNodeStore, NodeState> resultStates = newHashMap();
- for (MountedNodeStore mountedNodeStore :
ctx.getAllMountedNodeStores()) {
- NodeStore nodeStore = mountedNodeStore.getNodeStore();
- NodeBuilder partialBuilder =
nodeBuilder.getBuilders().get(mountedNodeStore);
- NodeState result = nodeStore.reset(partialBuilder);
- resultStates.put(mountedNodeStore, result);
+
+ 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();
}
return createRootNodeState(resultStates);
}
@@ -248,18 +274,24 @@ 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;
+
+ 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 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());
+ String newCheckpoint =
ctx.getGlobalStore().getNodeStore().checkpoint(lifetime, globalProperties);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Created checkpoint {}. Debug info:\n{}",
newCheckpoint, checkpointDebugInfo());
+ }
+ return newCheckpoint;
+ } finally {
+ lock.readLock().unlock();
}
- return newCheckpoint;
}
@Override