Author: chetanm
Date: Tue Oct 18 15:02:01 2016
New Revision: 1765455

URL: http://svn.apache.org/viewvc?rev=1765455&view=rev
Log:
OAK-1312 - Bundle nodes into a document

Add benchmark for bundling case. This does not depend on any code change in 
Bundling feature and just provisions the bundling config. This would allow us 
to check if bundling logic (even when not is use) have any adverse impact on 
performance

Added:
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java

Modified: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java?rev=1765455&r1=1765454&r2=1765455&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java
 Tue Oct 18 15:02:01 2016
@@ -415,7 +415,8 @@ public class BenchmarkRunner {
             new ExternalLoginTest(numberOfUsers.value(options), 
numberOfGroups.value(options), expiration.value(options), 
dynamicMembership.value(options), autoMembership.values(options)),
             new SyncAllExternalUsersTest(numberOfUsers.value(options), 
numberOfGroups.value(options), expiration.value(options), 
dynamicMembership.value(options), autoMembership.values(options)),
             new SyncExternalUsersTest(numberOfUsers.value(options), 
numberOfGroups.value(options), expiration.value(options), 
dynamicMembership.value(options), autoMembership.values(options), 
batchSize.value(options)),
-            new HybridIndexTest(base.value(options), statsProvider)
+            new HybridIndexTest(base.value(options), statsProvider),
+            new BundlingNodeTest()
         };
 
         Set<String> argset = Sets.newHashSet(nonOption.values(options));

Added: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java?rev=1765455&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java
 Tue Oct 18 15:02:01 2016
@@ -0,0 +1,383 @@
+/*
+ * 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.benchmark;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Queue;
+import java.util.Random;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.EvictingQueue;
+import org.apache.commons.collections.buffer.CircularFifoBuffer;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.commons.cnd.CndImporter;
+import org.apache.jackrabbit.commons.cnd.ParseException;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.fixture.JcrCreator;
+import org.apache.jackrabbit.oak.fixture.OakRepositoryFixture;
+import org.apache.jackrabbit.oak.fixture.RepositoryFixture;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.JcrConstants.NT_FOLDER;
+import static org.apache.jackrabbit.JcrConstants.NT_RESOURCE;
+import static org.apache.jackrabbit.commons.JcrUtils.getOrAddNode;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static 
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NT_OAK_RESOURCE;
+import static 
org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NT_OAK_UNSTRUCTURED;
+
+public class BundlingNodeTest extends 
AbstractTest<BundlingNodeTest.TestContext> {
+    enum Status {
+        NONE, STARTING, STARTED, STOPPING, STOPPED, ABORTED;
+
+        private int count;
+
+        public void inc(){
+            count++;
+        }
+
+        public int count(){
+            return count;
+        }
+
+        public Status next(){
+            Status[] ss = values();
+            if (ordinal() == ss.length - 1){
+                return ss[0];
+            }
+            return ss[ordinal() + 1];
+        }
+    }
+
+    private static final String NT_OAK_ASSET = "oak:Asset";
+
+    private static final String ASSET_NODE_TYPE_DEFN = "[oak:Asset]\n" +
+            " - * (UNDEFINED) multiple\n" +
+            " - * (UNDEFINED)\n" +
+            " + * (nt:base) = oak:Asset VERSION";
+
+    private final Random random = new Random(42); //fixed seed
+    private int nodesPerFolder = 10;
+
+    private boolean bundlingEnabled = 
Boolean.parseBoolean(System.getProperty("bundlingEnabled", "false"));
+    private boolean oakResourceEnabled = 
Boolean.parseBoolean(System.getProperty("oakResourceEnabled", "false"));
+    private boolean readerEnabled = 
Boolean.parseBoolean(System.getProperty("readerEnabled", "true"));
+    private RepositoryInitializer bundlingInitializer = new 
BundlingConfigInitializer();
+    private TestContext defaultContext;
+    private Reader reader;
+    private Mutator mutator;
+    private final AtomicInteger assetCount = new AtomicInteger();
+    private List<TestContext> contexts = new ArrayList<>();
+    private String contentNodeType = NT_RESOURCE;
+
+    @Override
+    protected Repository[] createRepository(RepositoryFixture fixture) throws 
Exception {
+        if (fixture instanceof OakRepositoryFixture) {
+            return ((OakRepositoryFixture) fixture).setUpCluster(1, new 
JcrCreator() {
+                @Override
+                public Jcr customize(Oak oak) {
+                    Jcr jcr = new Jcr(oak);
+                    if (bundlingEnabled) {
+                        jcr.with(bundlingInitializer);
+                    }
+                    return jcr;
+                }
+            });
+        }
+        return super.createRepository(fixture);
+    }
+
+    @Override
+    public void beforeSuite() throws Exception {
+        if (oakResourceEnabled) {
+            contentNodeType = NT_OAK_RESOURCE;
+        }
+        registerAssetNodeType();
+        defaultContext = new TestContext();
+        contexts.add(defaultContext);
+        reader = new Reader();
+        mutator = new Mutator();
+
+        if (readerEnabled) {
+            addBackgroundJob(reader);
+        }
+        addBackgroundJob(mutator);
+    }
+
+    @Override
+    protected TestContext prepareThreadExecutionContext() throws 
RepositoryException {
+        TestContext ctx = new TestContext();
+        contexts.add(ctx);
+        return ctx;
+    }
+
+    @Override
+    protected void runTest() throws Exception {
+        runTest(defaultContext);
+    }
+
+    @Override
+    protected void runTest(TestContext ctx)  throws Exception {
+        //Create tree in breadth first fashion with each node having 50 child
+        Node parent = ctx.session.getNode(ctx.paths.remove());
+        Status status = Status.NONE;
+        parent = parent.addNode(nextNodeName(), NT_OAK_UNSTRUCTURED);
+        for (int i = 0; i < nodesPerFolder; i++) {
+            Node asset = parent.addNode(nextNodeName()+".png", NT_OAK_ASSET);
+
+            createAssetNodeStructure(asset, status.name());
+
+            ctx.session.save();
+            ctx.addAssetPath(asset.getPath());
+            assetCount.incrementAndGet();
+            status.inc();
+            status = status.next();
+        }
+
+        ctx.addFolderPath(parent.getPath());
+    }
+
+    private void createAssetNodeStructure(Node asset, String status) throws 
RepositoryException {
+        Node content = asset.addNode("jcr:content", NT_OAK_UNSTRUCTURED);
+        Node metadata = content.addNode("metadata", NT_OAK_UNSTRUCTURED);
+        metadata.setProperty("status", status);
+
+        Node renditions = content.addNode("renditions", NT_FOLDER);
+        for (int i = 0; i < 5; i++) {
+            addFile(renditions, "thumbnail-" + i + ".png");
+        }
+
+        content.addNode("comments", NT_OAK_UNSTRUCTURED);
+    }
+
+    private void addFile(Node parent, String fileName) throws 
RepositoryException {
+        Node file = getOrAddNode(parent, fileName, NodeType.NT_FILE);
+        Node content = getOrAddNode(file, Node.JCR_CONTENT, contentNodeType);
+        content.setProperty(Property.JCR_MIMETYPE, "text/plain");
+        content.setProperty(Property.JCR_LAST_MODIFIED, 
Calendar.getInstance());
+
+        Binary binary = parent.getSession().getValueFactory().createBinary(new 
ByteArrayInputStream("hello".getBytes()));
+        content.setProperty(Property.JCR_DATA, binary);
+        binary.dispose();
+    }
+
+    @Override
+    protected void disposeThreadExecutionContext(TestContext context) throws 
RepositoryException {
+        context.dispose();
+    }
+
+    @Override
+    protected void afterSuite() throws Exception {
+        System.out.printf("bundlingEnabled: %s, oakResourceEnabled: %s, 
readerEnabled: %s%n",
+                bundlingEnabled, oakResourceEnabled, readerEnabled);
+    }
+
+    @Override
+    protected String[] statsNames() {
+        return new String[]{"Reader", "Mutator", "Assets#"};
+    }
+
+    @Override
+    protected String[] statsFormats() {
+        return new String[]{"%8d", "%6d", "%6d"};
+    }
+
+    @Override
+    protected Object[] statsValues() {
+        return new Object[]{reader.readCount, mutator.mutationCount, 
assetCount.get()};
+    }
+
+    @Override
+    protected String comment() {
+        List<String> commentElements = new ArrayList<>();
+        if (bundlingEnabled){
+            commentElements.add("bundling");
+        }
+        commentElements.add(contentNodeType);
+        return Joiner.on(',').join(commentElements);
+    }
+
+    protected class TestContext {
+        final Session session = loginWriter();
+        final Queue<String> paths = new LinkedBlockingDeque<>();
+        final int assetSampleSize = 50;
+        final EvictingQueue<String> buffer = 
EvictingQueue.create(assetSampleSize);
+        private List<String> assets;
+        private int assetCount = 0;
+
+
+        final Node dump;
+
+        public TestContext() throws RepositoryException {
+            dump = session.getRootNode()
+                    .addNode(nextNodeName(), NT_OAK_UNSTRUCTURED)
+                    .addNode(nextNodeName(), NT_OAK_UNSTRUCTURED);
+            session.save();
+            paths.add(dump.getPath());
+        }
+
+        public void dispose() throws RepositoryException {
+            dump.remove();
+            session.logout();
+        }
+
+        @CheckForNull
+        public String pickRandomPath(){
+            if (assets != null){
+                return assets.get(random.nextInt(assets.size()));
+            }
+            return buffer.peek();
+        }
+
+        public void addAssetPath(String path) {
+            buffer.add(path);
+            if (++assetCount % assetSampleSize == 0){
+                assets = new ArrayList<>(buffer);
+            }
+        }
+
+        public void addFolderPath(String path) {
+            paths.add(path);
+        }
+    }
+
+    private TestContext randomContext() {
+        return contexts.get(random.nextInt(contexts.size()));
+    }
+
+    private void registerAssetNodeType() throws ParseException, 
RepositoryException, IOException {
+        Session session = loginWriter();
+        CndImporter.registerNodeTypes(new StringReader(ASSET_NODE_TYPE_DEFN), 
session);
+        session.logout();
+    }
+
+    private class BundlingConfigInitializer implements RepositoryInitializer {
+        private static final String DOCUMENT_NODE_STORE = "documentstore";
+        private static final String BUNDLOR = "bundlor";
+
+        @Override
+        public void initialize(@Nonnull NodeBuilder builder) {
+            if (builder.hasChildNode(JCR_SYSTEM)){
+                NodeBuilder system = builder.getChildNode(JCR_SYSTEM);
+
+                if (!system.hasChildNode(DOCUMENT_NODE_STORE)){
+                    NodeBuilder dns = jcrChild(system, DOCUMENT_NODE_STORE);
+                    NodeBuilder bundlor = jcrChild(dns, BUNDLOR);
+
+                    addPattern(bundlor, "nt:file", "jcr:content");
+                    addPattern(bundlor, "oak:Asset", "jcr:content",
+                            "jcr:content/metadata",
+                            "jcr:content/renditions",
+                            "jcr:content/renditions/**"
+                    );
+
+                }
+            }
+        }
+
+        private void addPattern(NodeBuilder builder, String type, String ... 
patterns){
+            NodeBuilder child = jcrChild(builder, type);
+            child.setProperty(createProperty("pattern", 
Arrays.asList(patterns), STRINGS));
+        }
+
+        private NodeBuilder jcrChild(NodeBuilder builder, String name){
+            NodeBuilder child = builder.child(name);
+            child.setProperty(JcrConstants.JCR_PRIMARYTYPE, 
NodeTypeConstants.NT_OAK_UNSTRUCTURED, Type.NAME);
+            return child;
+        }
+    }
+
+    private class Reader implements Runnable {
+        final Session session = loginWriter();
+        int readCount = 0;
+        @Override
+        public void run() {
+            try{
+                run0();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private void run0() throws Exception {
+            for (int i = 0; i < 25; i++) {
+                String path = randomContext().pickRandomPath();
+                if (path != null) {
+                    session.refresh(false);
+                    Node asset = session.getNode(path);
+                    asset.getProperty("jcr:content/metadata/status");
+                    readCount++;
+                }
+            }
+            TimeUnit.MILLISECONDS.sleep(10);
+        }
+    }
+
+    private class Mutator implements Runnable {
+        final Session session = loginWriter();
+        int mutationCount = 0;
+        @Override
+        public void run() {
+            try{
+                run0();
+            } catch (RepositoryException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        private void run0() throws RepositoryException {
+            TestContext ctx = randomContext();
+            String path = ctx.pickRandomPath();
+            if (path != null){
+                session.refresh(false);
+                Node asset = session.getNode(path);
+                Node metadata = asset.getNode("jcr:content/metadata");
+                String status = metadata.getProperty("status").getString();
+                metadata.setProperty("status", 
Status.valueOf(status).next().name());
+                session.save();
+                mutationCount++;
+            }
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BundlingNodeTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to