diff --git a/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java b/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java index 26d5f48..6124d34 100644 --- a/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java +++ b/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/BenchmarkRunner.java @@ -253,6 +253,10 @@ public class BenchmarkRunner { runAsAdmin.value(options), itemsToRead.value(options), report.value(options)), + new ReadDeepTreeNoCacheTest( + runAsAdmin.value(options), + itemsToRead.value(options), + report.value(options)), new CompositeAuthorizationTest( runAsAdmin.value(options), itemsToRead.value(options)), // NOTE: this is currently the no of configurations diff --git a/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/ReadDeepTreeNoCacheTest.java b/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/ReadDeepTreeNoCacheTest.java new file mode 100644 index 0000000..d4f7943 --- /dev/null +++ b/oak-run/src/main/java/org/apache/jackrabbit/oak/benchmark/ReadDeepTreeNoCacheTest.java @@ -0,0 +1,200 @@ +/* + * 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 com.codahale.metrics.Metric; +import com.codahale.metrics.MetricFilter; +import com.codahale.metrics.Slf4jReporter; +import com.google.common.util.concurrent.MoreExecutors; +import org.apache.commons.lang.StringUtils; +import org.apache.jackrabbit.oak.Oak; +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.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.DocumentStoreStats; +import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore; +import org.apache.jackrabbit.oak.plugins.document.util.LeaseCheckDocumentStoreWrapper; +import org.apache.jackrabbit.oak.plugins.metric.MetricStatisticsProvider; +import org.apache.jackrabbit.oak.stats.StatisticsProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.jcr.ImportUUIDBehavior; +import javax.jcr.ItemVisitor; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Value; +import javax.jcr.ValueFactory; +import javax.jcr.util.TraversingItemVisitor; +import javax.management.MBeanServer; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ReadDeepTreeNoCacheTest extends ReadDeepTreeTest { + + private static final Logger log = LoggerFactory.getLogger(ReadDeepTreeNoCacheTest.class); + + private static final int BATCHES = 5; + + public ReadDeepTreeNoCacheTest(boolean runAsAdmin, int itemsToRead, boolean doReport) { + super(runAsAdmin, itemsToRead, doReport); + } + + @Override + protected void beforeSuite() throws Exception { + adminSession = loginWriter(); + ValueFactory vf = adminSession.getValueFactory(); + + Node rn = adminSession.getRootNode(); + String testNodeName = getTestNodeName(); + String pathsNodeName = testNodeName + "-paths"; + + if (rn.hasNode(testNodeName) && rn.hasNode(pathsNodeName)) { + allPaths.clear(); + for (Value v : rn.getProperty(pathsNodeName + "/paths").getValues()) { + for (int i = 0; i < BATCHES; i++) { + allPaths.add(String.format("/%s/batch%d/%s", getTestNodeName(), i, v.getString())); + } + } + System.out.println("Read list of the " + allPaths.size() + " paths from the repository"); + } else { + createDeepTree(); + Node pathContainer = rn.addNode(pathsNodeName, "nt:unstructured"); + + String[] suffixes = new String[allPaths.size()]; + int i = 0; + for (String p : allPaths) { + p = StringUtils.substringAfter(p, "/" + getTestNodeName() + "/batch0/"); + suffixes[i++] = p; + } + pathContainer.setProperty("paths", suffixes); + adminSession.save(); + issueHaltRequest("Test content has been set up"); + } + + testSession = singleSession ? getTestSession() : null; + } + + protected void createDeepTree() throws Exception { + allPaths.clear(); + + String testNodeName = getTestNodeName(); + testRoot = adminSession.getRootNode().addNode(testNodeName, "nt:unstructured"); + for (int i = 0; i < BATCHES; i++) { + long start = System.currentTimeMillis(); + + Node batchRoot = testRoot.addNode("batch" + i, "nt:unstructured"); + InputStream in = getClass().getClassLoader().getResourceAsStream(getImportFileName()); + adminSession.importXML(batchRoot.getPath(), in, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW); + adminSession.save(); + + System.out.println(String.format("Imported batch %d in %ds", i, (System.currentTimeMillis()-start) / 1000)); + } + + ItemVisitor v = new TraversingItemVisitor.Default() { + @Override + protected void entering(Node node, int i) throws RepositoryException { + visitingNode(node, i); + super.entering(node, i); + } + @Override + protected void entering(Property prop, int i) throws RepositoryException { + visitingProperty(prop, i); + super.entering(prop, i); + } + }; + v.visit(testRoot.getNode("batch0")); + + System.out.println("All paths: " + allPaths.size() * BATCHES); + } + + protected String getTestNodeName() { + return getClass().getSimpleName(); + } + + @Override + protected void afterSuite() throws Exception { + // don't remove the paths + } + + @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) { + boolean enableMetrics = Boolean.getBoolean("enableMetrics"); + if (enableMetrics) { + log.info("Enabling Metrics integration"); + + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + ScheduledExecutorService executor = + MoreExecutors.getExitingScheduledExecutorService(new ScheduledThreadPoolExecutor(1)); + MetricStatisticsProvider statsProvider = new MetricStatisticsProvider(server, executor); + oak.getWhiteboard().register(StatisticsProvider.class, + statsProvider, Collections.emptyMap()); + + MongoDocumentStore ds = getDS(oak); + if (ds != null) { + ds.setStatsCollector(new DocumentStoreStats(statsProvider)); + } + + final Slf4jReporter reporter = Slf4jReporter.forRegistry(statsProvider.getRegistry()) + .outputTo(LoggerFactory.getLogger("org.apache.jackrabbit.oak.metrics")) + .convertRatesTo(TimeUnit.SECONDS) + .convertDurationsTo(TimeUnit.MICROSECONDS) + .filter(new MetricFilter() { + @Override + public boolean matches(String name, Metric metric) { + return name.contains("PRIMARY") || name.contains("SLAVE"); + } + }) + .build(); + reporter.start(30, TimeUnit.SECONDS); + } + return new Jcr(oak); + } + }); + } + return super.createRepository(fixture); + } + + private static MongoDocumentStore getDS(Oak oak) { + try { + Field storeField = Oak.class.getDeclaredField("store"); + storeField.setAccessible(true); + DocumentNodeStore ns = (DocumentNodeStore) storeField.get(oak); + LeaseCheckDocumentStoreWrapper wrapper = (LeaseCheckDocumentStoreWrapper) ns.getDocumentStore(); + + Field delegateField = LeaseCheckDocumentStoreWrapper.class.getDeclaredField("delegate"); + delegateField.setAccessible(true); + return (MongoDocumentStore) delegateField.get(wrapper); + } catch (Exception e) { + log.error("can't get mongo document store", e); + return null; + } + } +}