Author: mreutegg
Date: Mon Feb 23 09:53:58 2015
New Revision: 1661630
URL: http://svn.apache.org/r1661630
Log:
OAK-2501: add more trace-logging to mongoMk to debug performance issues
Apply patch from Stefan Egli
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.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/mongo/MongoDocumentStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java?rev=1661630&r1=1661629&r2=1661630&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeState.java
Mon Feb 23 09:53:58 2015
@@ -48,6 +48,8 @@ import org.apache.jackrabbit.oak.spi.sta
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
+import org.apache.jackrabbit.oak.util.PerfLogger;
+import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
@@ -63,6 +65,10 @@ import static org.apache.jackrabbit.oak.
*/
public class DocumentNodeState extends AbstractNodeState implements CacheValue
{
+ private static final PerfLogger perfLogger = new PerfLogger(
+ LoggerFactory.getLogger(DocumentNodeState.class.getName()
+ + ".perf"));
+
public static final Children NO_CHILDREN = new Children();
/**
@@ -257,7 +263,19 @@ public class DocumentNodeState extends A
return true;
} else {
// use DocumentNodeStore compare
- return dispatch(store.diffChildren(this, mBase),
mBase, diff);
+ final long start = perfLogger.start();
+ try {
+ return dispatch(store.diffChildren(this, mBase),
+ mBase, diff);
+ } finally {
+ perfLogger
+ .end(start,
+ 1,
+ "compareAgainstBaseState, path={},
rev={}, lastRevision={}, base.path={}, base.rev={}, base.lastRevision={}",
+ path, rev, lastRevision,
+ mBase.path, mBase.rev,
+ mBase.lastRevision);
+ }
}
}
}
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=1661630&r1=1661629&r2=1661630&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
Mon Feb 23 09:53:58 2015
@@ -98,6 +98,7 @@ import org.apache.jackrabbit.oak.spi.sta
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.apache.jackrabbit.oak.stats.Clock;
+import org.apache.jackrabbit.oak.util.PerfLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -109,6 +110,9 @@ public final class DocumentNodeStore
private static final Logger LOG =
LoggerFactory.getLogger(DocumentNodeStore.class);
+ private static final PerfLogger PERFLOG = new PerfLogger(
+ LoggerFactory.getLogger(DocumentNodeStore.class.getName() +
".perf"));
+
/**
* Do not cache more than this number of children for a document.
*/
@@ -698,6 +702,7 @@ public final class DocumentNodeStore
@CheckForNull
DocumentNodeState getNode(@Nonnull final String path, @Nonnull final
Revision rev) {
checkRevisionAge(checkNotNull(rev), checkNotNull(path));
+ final long start = PERFLOG.start();
try {
PathRev key = new PathRev(path, rev);
DocumentNodeState node = nodeCache.get(key, new
Callable<DocumentNodeState>() {
@@ -714,7 +719,10 @@ public final class DocumentNodeStore
return n;
}
});
- return node == missing || node.equals(missing) ? null : node;
+ final DocumentNodeState result = node == missing
+ || node.equals(missing) ? null : node;
+ PERFLOG.end(start, 1, "getNode: path={}, rev={}", path, rev);
+ return result;
} catch (UncheckedExecutionException e) {
throw DocumentStoreException.convert(e.getCause());
} catch (ExecutionException e) {
@@ -936,13 +944,21 @@ public final class DocumentNodeStore
@CheckForNull
DocumentNodeState readNode(String path, Revision readRevision) {
+ final long start = PERFLOG.start();
String id = Utils.getIdFromPath(path);
Revision lastRevision = getPendingModifications().get(path);
NodeDocument doc = store.find(Collection.NODES, id);
if (doc == null) {
+ PERFLOG.end(start, 1,
+ "readNode: (document not found) path={}, readRevision={}",
+ path, readRevision);
return null;
}
- return doc.getNodeAtRevision(this, readRevision, lastRevision);
+ final DocumentNodeState result = doc.getNodeAtRevision(this,
+ readRevision, lastRevision);
+ PERFLOG.end(start, 1, "readNode: path={}, readRevision={}", path,
+ readRevision);
+ return result;
}
/**
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1661630&r1=1661629&r2=1661630&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
Mon Feb 23 09:53:58 2015
@@ -63,6 +63,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
import org.apache.jackrabbit.oak.plugins.document.util.Utils;
import org.apache.jackrabbit.oak.stats.Clock;
+import org.apache.jackrabbit.oak.util.PerfLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -91,8 +92,9 @@ import static com.google.common.base.Pre
public class MongoDocumentStore implements DocumentStore {
private static final Logger LOG =
LoggerFactory.getLogger(MongoDocumentStore.class);
-
- private static final boolean LOG_TIME = false;
+ private static final PerfLogger PERFLOG = new PerfLogger(
+ LoggerFactory.getLogger(MongoDocumentStore.class.getName()
+ + ".perf"));
private static final DBObject BY_ID_ASC = new BasicDBObject(Document.ID,
1);
@@ -239,20 +241,6 @@ public class MongoDocumentStore implemen
return new NodeDocOffHeapCache(primaryCache, listener, builder, this);
}
- private static long start() {
- return LOG_TIME ? System.currentTimeMillis() : 0;
- }
-
- private void end(String message, long start) {
- if (LOG_TIME) {
- long t = System.currentTimeMillis() - start;
- if (t > 0) {
- LOG.debug(message + ": " + t);
- }
- timeSum += t;
- }
- }
-
@Override
public void finalize() throws Throwable {
super.finalize();
@@ -289,14 +277,20 @@ public class MongoDocumentStore implemen
@Override
public <T extends Document> T find(Collection<T> collection, String key) {
- return find(collection, key, true, -1);
+ final long start = PERFLOG.start();
+ final T result = find(collection, key, true, -1);
+ PERFLOG.end(start, 1, "find: preferCached=true, key={}", key);
+ return result;
}
@Override
public <T extends Document> T find(final Collection<T> collection,
final String key,
int maxCacheAge) {
- return find(collection, key, false, maxCacheAge);
+ final long start = PERFLOG.start();
+ final T result = find(collection, key, false, maxCacheAge);
+ PERFLOG.end(start, 1, "find: preferCached=false, key={}", key);
+ return result;
}
@SuppressWarnings("unchecked")
@@ -409,12 +403,14 @@ public class MongoDocumentStore implemen
protected <T extends Document> T findUncached(Collection<T> collection,
String key, DocumentReadPreference docReadPref) {
log("findUncached", key, docReadPref);
DBCollection dbCollection = getDBCollection(collection);
- long start = start();
+ final long start = PERFLOG.start();
+ boolean isSlaveOk = false;
try {
ReadPreference readPreference = getMongoReadPreference(collection,
Utils.getParentId(key), docReadPref);
if(readPreference.isSlaveOk()){
LOG.trace("Routing call to secondary for fetching [{}]", key);
+ isSlaveOk = true;
}
DBObject obj = dbCollection.findOne(getByKeyQuery(key).get(),
null, null, readPreference);
@@ -439,7 +435,8 @@ public class MongoDocumentStore implemen
}
return doc;
} finally {
- end("findUncached", start);
+ PERFLOG.end(start, 1, "findUncached on key={}, isSlaveOk={}", key,
+ isSlaveOk);
}
}
@@ -490,7 +487,7 @@ public class MongoDocumentStore implemen
DBObject query = queryBuilder.get();
String parentId = Utils.getParentIdFromLowerLimit(fromKey);
TreeLock lock = acquireExclusive(parentId != null ? parentId : "");
- long start = start();
+ final long start = PERFLOG.start();
try {
DBCursor cursor =
dbCollection.find(query).sort(BY_ID_ASC).hint(hint);
ReadPreference readPreference =
@@ -538,7 +535,7 @@ public class MongoDocumentStore implemen
return list;
} finally {
lock.unlock();
- end("query", start);
+ PERFLOG.end(start, 1, "query for children from [{}] to [{}]",
fromKey, toKey);
}
}
@@ -553,7 +550,7 @@ public class MongoDocumentStore implemen
public <T extends Document> void remove(Collection<T> collection, String
key) {
log("remove", key);
DBCollection dbCollection = getDBCollection(collection);
- long start = start();
+ long start = PERFLOG.start();
try {
WriteResult writeResult =
dbCollection.remove(getByKeyQuery(key).get());
invalidateCache(collection, key);
@@ -561,7 +558,7 @@ public class MongoDocumentStore implemen
throw new DocumentStoreException("Remove failed: " +
writeResult.getError());
}
} finally {
- end("remove", start);
+ PERFLOG.end(start, 1, "remove key={}", key);
}
}
@@ -591,7 +588,7 @@ public class MongoDocumentStore implemen
DBObject update = createUpdate(updateOp);
TreeLock lock = acquire(updateOp.getId());
- long start = start();
+ final long start = PERFLOG.start();
try {
// get modCount of cached document
Number modCount = null;
@@ -644,7 +641,7 @@ public class MongoDocumentStore implemen
throw DocumentStoreException.convert(e);
} finally {
lock.unlock();
- end("findAndModify", start);
+ PERFLOG.end(start, 1, "findAndModify [{}]", updateOp.getId());
}
}
@@ -714,7 +711,7 @@ public class MongoDocumentStore implemen
}
DBCollection dbCollection = getDBCollection(collection);
- long start = start();
+ final long start = PERFLOG.start();
try {
try {
WriteResult writeResult = dbCollection.insert(inserts);
@@ -736,7 +733,7 @@ public class MongoDocumentStore implemen
return false;
}
} finally {
- end("create", start);
+ PERFLOG.end(start, 1, "create");
}
}
@@ -750,7 +747,7 @@ public class MongoDocumentStore implemen
// make sure we don't modify the original updateOp
updateOp = updateOp.copy();
DBObject update = createUpdate(updateOp);
- long start = start();
+ final long start = PERFLOG.start();
try {
Map<String, NodeDocument> cachedDocs = Collections.emptyMap();
if (collection == Collection.NODES) {
@@ -786,7 +783,7 @@ public class MongoDocumentStore implemen
throw DocumentStoreException.convert(e);
}
} finally {
- end("update", start);
+ PERFLOG.end(start, 1, "update");
}
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java?rev=1661630&r1=1661629&r2=1661630&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/observation/EventGenerator.java
Mon Feb 23 09:53:58 2015
@@ -36,7 +36,7 @@ import javax.annotation.Nonnull;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
-import org.slf4j.Logger;
+import org.apache.jackrabbit.oak.util.PerfLogger;
import org.slf4j.LoggerFactory;
/**
@@ -55,7 +55,10 @@ import org.slf4j.LoggerFactory;
* </pre>
*/
public class EventGenerator {
- private static final Logger log =
LoggerFactory.getLogger(EventGenerator.class);
+
+ private static final PerfLogger perfLogger = new PerfLogger(
+ LoggerFactory.getLogger(EventGenerator.class.getName()
+ + ".perf"));
/**
* Maximum number of content changes to process during the
@@ -109,14 +112,11 @@ public class EventGenerator {
public void generate() {
if (!continuations.isEmpty()) {
final Continuation c = continuations.removeFirst();
- if (log.isDebugEnabled()) {
- log.debug("Starting event generation ...");
- long start = System.currentTimeMillis();
- c.run();
- log.debug("Generated {} events in {} ms", c.counter,
(System.currentTimeMillis() - start));
- } else {
- c.run();
- }
+ final long start = perfLogger
+ .start("generate: Starting event generation");
+ c.run();
+ perfLogger.end(start, 1, "generate: Generated {} events in {} ms",
+ c.counter);
}
}
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java?rev=1661630&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java
Mon Feb 23 09:53:58 2015
@@ -0,0 +1,199 @@
+/*
+ * 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.util;
+
+import org.slf4j.Logger;
+
+/**
+ * PerfLogger is a simpler wrapper around a slf4j Logger which
+ * comes with the capability to issue log statements containing
+ * the measurement between start() and end() methods.
+ * <p>
+ * Usage:
+ * <ul>
+ * <li>final long start = perflogger.start();</li>
+ * <li>.. some code ..
+ * <li>perflogger.end(start, 1, "myMethodName: param1={}", param1);</li>
+ * </ul>
+ * <p>
+ * The above will do nothing if the log level for the logger passed
+ * to PerfLogger at construction time is not DEBUG or TRACE - otherwise
+ * start() will return the current time in milliseconds and end will
+ * issue a log statement if the time between start and end was bigger
+ * than 1 ms, and it will pass the parameters to the log statement.
+ * The idea is to keep up performance at max possible if the log
+ * level is INFO or higher - but to allow some meaningful logging
+ * if at DEBUG or TRACe. The difference between DEBUG and TRACE is
+ * that TRACE will log start too (if a log message is passed to start)
+ * and it will always log the end - whereas in case of DEBUG the start
+ * will never be logged and the end will only be logged if the time
+ * is bigger than what's passed to end.
+ */
+public final class PerfLogger {
+
+ /** The logger to which the log statements are emitted **/
+ private final Logger delegate;
+
+ /** Create a new PerfLogger that shall use the given Logger object for
logging **/
+ public PerfLogger(Logger delegate) {
+ if (delegate == null) {
+ throw new IllegalArgumentException("delegate must not be null");
+ }
+ this.delegate = delegate;
+ }
+
+ /**
+ * Returns quickly if log level is not DEBUG or TRACE - otherwise just
+ * returns the current time in millis.
+ *
+ * @return the current time if level is DEBUG or TRACE, -1 otherwise
+ */
+ public final long start() {
+ if (!delegate.isDebugEnabled()) {
+ // if log level is not at least DEBUG, then return fast, no-op
+ return -1;
+ }
+ return start(null);
+ }
+
+ /**
+ * Returns quickly if log level is not DEBUG or TRACE - if it is DEBUG,
then
+ * just returns the current time in millis, if it is TRACE, then log the
+ * given message and also return the current time in millis.
+ *
+ * @param traceMsgOrNull
+ * the message to log if log level is TRACE - or null if no
+ * message should be logged (even on TRACE level)
+ * @return the current time if level is DEBUG or TRACE, -1 otherwise
+ */
+ public final long start(String traceMsgOrNull) {
+ if (!delegate.isDebugEnabled()) {
+ // if log level is not at least DEBUG, then return fast, no-op
+ return -1;
+ }
+ if (traceMsgOrNull != null && delegate.isTraceEnabled()) {
+ delegate.trace(traceMsgOrNull);
+ }
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * Returns quickly if log level is not DEBUG or TRACE - if it is DEBUG
+ * and the difference between now and the provided 'start' is bigger
(slower)
+ * than 'logAtDebugIfSlowerThanMs', then a log.debug is emitted, if at
+ * TRACE then a log.trace is always emitted (independent of time measured).
+ * <p>
+ * Note that this method exists for performance optimization only (compared
+ * to the other end() method with a vararg.
+ * @param start the start time with which 'now' should be compared
+ * @param logAtDebugIfSlowerThanMs the number of milliseconds that must
+ * be surpassed to issue a log.debug (if log level is DEBUG)
+ * @param logMessagePrefix the log message 'prefix' - to which the given
+ * argument will be passed, plus the measured time difference in the format
+ * '[took x ms']
+ * @param arg1 the argument which is to be passed to the log statement
+ */
+ public final void end(long start, long logAtDebugIfSlowerThanMs,
+ String logMessagePrefix, Object arg1) {
+ if (!delegate.isTraceEnabled()) {
+ return;
+ }
+ end(start, logAtDebugIfSlowerThanMs, logMessagePrefix,
+ new Object[] { arg1 });
+ }
+
+ /**
+ * Returns quickly if log level is not DEBUG or TRACE - if it is DEBUG
+ * and the difference between now and the provided 'start' is bigger
(slower)
+ * than 'logAtDebugIfSlowerThanMs', then a log.debug is emitted, if at
+ * TRACE then a log.trace is always emitted (independent of time measured).
+ * <p>
+ * Note that this method exists for performance optimization only (compared
+ * to the other end() method with a vararg.
+ * @param start the start time with which 'now' should be compared
+ * @param logAtDebugIfSlowerThanMs the number of milliseconds that must
+ * be surpassed to issue a log.debug (if log level is DEBUG)
+ * @param logMessagePrefix the log message 'prefix' - to which the given
+ * arguments will be passed, plus the measured time difference in the
format
+ * '[took x ms']
+ * @param arg1 the first argument which is to be passed to the log
statement
+ * @param arg2 the second argument which is to be passed to the log
statement
+ */
+ public final void end(long start, long logAtDebugIfSlowerThanMs,
+ String logMessagePrefix, Object arg1, Object arg2) {
+ if (!delegate.isTraceEnabled()) {
+ return;
+ }
+ end(start, logAtDebugIfSlowerThanMs, logMessagePrefix, new Object[] {
+ arg1, arg2 });
+ }
+
+ /**
+ * Returns quickly if log level is not DEBUG or TRACE - if it is DEBUG
+ * and the difference between now and the provided 'start' is bigger
(slower)
+ * than 'logAtDebugIfSlowerThanMs', then a log.debug is emitted, if at
+ * TRACE then a log.trace is always emitted (independent of time measured).
+ * @param start the start time with which 'now' should be compared
+ * @param logAtDebugIfSlowerThanMs the number of milliseconds that must
+ * be surpassed to issue a log.debug (if log level is DEBUG)
+ * @param logMessagePrefix the log message 'prefix' - to which the given
+ * arguments will be passed, plus the measured time difference in the
format
+ * '[took x ms']
+ * @param arguments the arguments which is to be passed to the log
statement
+ */
+ public void end(long start, long logAtDebugIfSlowerThanMs,
+ String logMessagePrefix, Object... arguments) {
+ if (!delegate.isDebugEnabled()) {
+ // if log level is not at least DEBUG, then return fast, no-op
+ return;
+ }
+
+ if (start == -1) {
+ // start was never set
+ // -> then log at trace as we have no diff available
+ delegate.trace(logMessagePrefix + " [start not set]",
+ (Object[]) arguments);
+ } else {
+ final long diff = System.currentTimeMillis() - start;
+ if (delegate.isTraceEnabled()) {
+ // if log level is TRACE, then always log - and do that on
TRACE
+ // then:
+ delegate.trace(logMessagePrefix + " [took " + diff + "ms]",
+ (Object[]) arguments);
+ } else if ((logAtDebugIfSlowerThanMs < 0)
+ || (diff > logAtDebugIfSlowerThanMs)) {
+ // otherwise (log level is DEBUG) only log if
+ // logDebugIfSlowerThanMs is set to -1 (or negative)
+ // OR the measured diff is larger than logDebugIfSlowerThanMs -
+ // and then do that on DEBUG:
+ delegate.debug(logMessagePrefix + " [took " + diff + "ms]",
+ (Object[]) arguments);
+ }
+ }
+ }
+
+ /** Whether or not the delegate has log level DEBUG configured **/
+ public final boolean isDebugEnabled() {
+ return delegate.isDebugEnabled();
+ }
+
+ /** Whether or not the delegate has log level TRACE configured **/
+ public final boolean isTraceEnabled() {
+ return delegate.isTraceEnabled();
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/util/PerfLogger.java
------------------------------------------------------------------------------
svn:eol-style = native