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


Reply via email to