Author: mreutegg
Date: Wed Aug 31 10:22:58 2016
New Revision: 1758576
URL: http://svn.apache.org/viewvc?rev=1758576&view=rev
Log:
OAK-4724: Prefetch external changes
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1758576&r1=1758575&r2=1758576&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
Wed Aug 31 10:22:58 2016
@@ -568,6 +568,7 @@ public class DocumentMK {
private boolean useSimpleRevision;
private long maxReplicationLagMillis = TimeUnit.HOURS.toMillis(6);
private boolean disableBranches;
+ private boolean prefetchExternalChanges;
private Clock clock = Clock.SIMPLE;
private Executor executor;
private String persistentCacheURI = DEFAULT_PERSISTENT_CACHE_URI;
@@ -1027,6 +1028,15 @@ public class DocumentMK {
return disableBranches;
}
+ public Builder setPrefetchExternalChanges(boolean b) {
+ prefetchExternalChanges = b;
+ return this;
+ }
+
+ public boolean isPrefetchExternalChanges() {
+ return prefetchExternalChanges;
+ }
+
VersionGCSupport createVersionGCSupport() {
DocumentStore store = getDocumentStore();
if (store instanceof MongoDocumentStore) {
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1758576&r1=1758575&r2=1758576&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
Wed Aug 31 10:22:58 2016
@@ -529,7 +529,9 @@ public final class DocumentNodeStore
// initialize branchCommits
branches.init(store, this);
- dispatcher = new ChangeDispatcher(getRoot());
+ dispatcher = builder.isPrefetchExternalChanges() ?
+ new PrefetchDispatcher(getRoot(), executor) :
+ new ChangeDispatcher(getRoot());
commitQueue = new CommitQueue(this);
String threadNamePostfix = "(" + clusterId + ")";
batchCommitQueue = new BatchCommitQueue(store);
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1758576&r1=1758575&r2=1758576&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
Wed Aug 31 10:22:58 2016
@@ -253,6 +253,13 @@ public class DocumentNodeStoreService {
)
public static final String PROP_JOURNAL_GC_BATCH_SIZE =
"journalGcBatchSize";
+ @Property (boolValue = false,
+ label = "Pre-fetch external changes",
+ description = "Boolean value indicating if external changes should
" +
+ "be pre-fetched in a background thread."
+ )
+ public static final String PROP_PREFETCH_EXTERNAL_CHANGES =
"prefetchExternalChanges";
+
private static final long MB = 1024 * 1024;
private static enum DocumentStoreType {
@@ -418,6 +425,7 @@ public class DocumentNodeStoreService {
String journalCache =
PropertiesUtil.toString(prop(PROP_JOURNAL_CACHE), DEFAULT_JOURNAL_CACHE);
int cacheSegmentCount = toInteger(prop(PROP_CACHE_SEGMENT_COUNT),
DEFAULT_CACHE_SEGMENT_COUNT);
int cacheStackMoveDistance =
toInteger(prop(PROP_CACHE_STACK_MOVE_DISTANCE),
DEFAULT_CACHE_STACK_MOVE_DISTANCE);
+ boolean prefetchExternalChanges =
toBoolean(prop(PROP_PREFETCH_EXTERNAL_CHANGES), false);
DocumentMK.Builder mkBuilder =
new DocumentMK.Builder().
setStatisticsProvider(statisticsProvider).
@@ -450,7 +458,8 @@ public class DocumentNodeStoreService {
// plan B succeeded.
}
}
- });
+ }).
+ setPrefetchExternalChanges(prefetchExternalChanges);
if (persistentCache != null && persistentCache.length() > 0) {
mkBuilder.setPersistentCache(persistentCache);
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java?rev=1758576&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java
Wed Aug 31 10:22:58 2016
@@ -0,0 +1,96 @@
+/*
+ * 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.plugins.document;
+
+import java.util.concurrent.Executor;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.ChangeDispatcher;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorDiff;
+import org.apache.jackrabbit.oak.spi.commit.VisibleEditor;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A change dispatcher that pre-fetches visible external changes in a
background
+ * task.
+ */
+class PrefetchDispatcher extends ChangeDispatcher {
+
+ private final Executor executor;
+ private NodeState root;
+
+ public PrefetchDispatcher(@Nonnull NodeState root,
+ @Nonnull Executor executor) {
+ super(root);
+ this.root = root;
+ this.executor = checkNotNull(executor);
+ }
+
+ @Override
+ public synchronized void contentChanged(@Nonnull NodeState root,
+ @Nullable CommitInfo info) {
+ if (root instanceof DocumentNodeState) {
+ final DocumentNodeState state = (DocumentNodeState) root;
+ if (state.isFromExternalChange()) {
+ executor.execute(new Runnable() {
+ private final NodeState before =
PrefetchDispatcher.this.root;
+ @Override
+ public void run() {
+ EditorDiff.process(
+ new VisibleEditor(TraversingEditor.INSTANCE),
+ before, state);
+ }
+ });
+ }
+ }
+ super.contentChanged(root, info);
+ this.root = root;
+ }
+
+ private static final class TraversingEditor extends DefaultEditor {
+
+ static final Editor INSTANCE = new TraversingEditor();
+
+ @Override
+ public Editor childNodeAdded(String name, NodeState after)
+ throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeChanged(String name,
+ NodeState before,
+ NodeState after)
+ throws CommitFailedException {
+ return this;
+ }
+
+ @Override
+ public Editor childNodeDeleted(String name, NodeState before)
+ throws CommitFailedException {
+ return this;
+ }
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java?rev=1758576&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java
Wed Aug 31 10:22:58 2016
@@ -0,0 +1,82 @@
+/*
+ * 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.plugins.document;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.Nonnull;
+
+import com.google.common.util.concurrent.MoreExecutors;
+
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class PrefetchDispatcherTest {
+
+ @Rule
+ public DocumentMKBuilderProvider builderProvider = new
DocumentMKBuilderProvider();
+
+ @Test
+ public void prefetchVisibleChanges() throws Exception {
+ final AtomicInteger numQueries = new AtomicInteger();
+ MemoryDocumentStore store = new MemoryDocumentStore() {
+ @Nonnull
+ @Override
+ public <T extends Document> List<T> query(Collection<T> collection,
+ String fromKey,
+ String toKey,
+ int limit) {
+ if (collection == Collection.NODES) {
+ numQueries.incrementAndGet();
+ }
+ return super.query(collection, fromKey, toKey, limit);
+ }
+ };
+ DocumentNodeStore ns1 = builderProvider.newBuilder()
+ .setDocumentStore(store).setClusterId(1)
+ .setPrefetchExternalChanges(false)
+ .setAsyncDelay(0).getNodeStore();
+ DocumentNodeStore ns2 = builderProvider.newBuilder()
+ .setDocumentStore(store).setClusterId(2)
+ .setPrefetchExternalChanges(false)
+ .setAsyncDelay(0).getNodeStore();
+
+ NodeBuilder builder = ns1.getRoot().builder();
+ builder.child("foo").child("bar").child("baz");
+ builder.child(":hidden").child("foo").child("bar");
+ ns1.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+ ns1.runBackgroundOperations();
+
+ DocumentNodeState before = ns2.getRoot();
+ ns2.runBackgroundOperations();
+ DocumentNodeState after = ns2.getRoot().fromExternalChange();
+
+ PrefetchDispatcher dispatcher = new PrefetchDispatcher(
+ before, MoreExecutors.sameThreadExecutor());
+ numQueries.set(0);
+ dispatcher.contentChanged(after, null);
+ // expect two queries for children: below /foo and /foo/bar
+ assertEquals(2, numQueries.get());
+ }
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/PrefetchDispatcherTest.java
------------------------------------------------------------------------------
svn:eol-style = native