Author: mduerig
Date: Wed Mar 4 10:46:46 2015
New Revision: 1663927
URL: http://svn.apache.org/r1663927
Log:
OAK-2564: SessionMBean should provide information about pending refresh
Add getRefreshStrategy and getRefreshPending to SessionMBean
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/SessionMBean.java
jackrabbit/oak/trunk/oak-doc/src/site/markdown/differences.md
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/RefreshStrategy.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionStats.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/SessionMBean.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/SessionMBean.java?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/SessionMBean.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/SessionMBean.java
Wed Mar 4 10:46:46 2015
@@ -78,6 +78,16 @@ public interface SessionMBean {
String getLastRefresh();
/**
+ * @return description of the refresh strategy
+ */
+ String getRefreshStrategy();
+
+ /**
+ * @return {@code true} iff the session will be refreshed on next access.
+ */
+ boolean getRefreshPending();
+
+ /**
* @return number of refresh operations
*/
long getRefreshCount();
Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/differences.md
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/differences.md?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/differences.md (original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/differences.md Wed Mar 4
10:46:46 2015
@@ -61,6 +61,9 @@ relying on one session seeing the other
> details regarding session backwards compatibility and
> [OAK-960](https://issues.apache.org/jira/browse/OAK-960) regarding in thread
> session
> synchronisation.
+>
+> The `SessionMBean` provides further information on when a session is
refreshed and wheter
+> a refresh will happen on the next access.
On Oak `Item.refresh()` is deprecated and will always cause an
`Session.refresh()`. The former call
will result in a warning written to the log in order to facilitate locating
trouble spots.
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
Wed Mar 4 10:46:46 2015
@@ -76,23 +76,9 @@ public class SessionDelegate {
private final ContentSession contentSession;
private final SecurityProvider securityProvider;
+ private final RefreshAtNextAccess refreshAtNextAccess = new
RefreshAtNextAccess();
+ private final SaveCountRefresh saveCountRefresh;
private final RefreshStrategy refreshStrategy;
- private boolean refreshAtNextAccess = false;
-
- /**
- * The repository-wide {@link ThreadLocal} that keeps track of the number
- * of saves performed in each thread.
- */
- private final ThreadLocal<Long> threadSaveCount;
-
- /**
- * Local copy of the {@link #threadSaveCount} for the current thread.
- * If the repository-wide counter differs from our local copy, then
- * some other session would have done a commit or this session is
- * being accessed from some other thread. In either case it's best to
- * refresh this session to avoid unexpected behaviour.
- */
- private long sessionSaveCount;
private final Root root;
private final IdentifierManager idManager;
@@ -147,14 +133,14 @@ public class SessionDelegate {
@Nonnull Clock clock) {
this.contentSession = checkNotNull(contentSession);
this.securityProvider = checkNotNull(securityProvider);
- this.refreshStrategy = checkNotNull(refreshStrategy);
- this.threadSaveCount = checkNotNull(threadSaveCount);
- this.sessionSaveCount = getThreadSaveCount();
+ this.saveCountRefresh = new
SaveCountRefresh(checkNotNull(threadSaveCount));
+ this.refreshStrategy = RefreshStrategy.Composite.create(
+ checkNotNull(refreshStrategy), refreshAtNextAccess,
saveCountRefresh);
this.root = contentSession.getLatestRoot();
this.idManager = new IdentifierManager(root);
this.clock = checkNotNull(clock);
this.sessionStats = new SessionStats(contentSession.toString(),
- contentSession.getAuthInfo(), clock);
+ contentSession.getAuthInfo(), clock, refreshStrategy);
this.sessionCounters = sessionStats.getCounters();
checkNotNull(statisticManager);
readCounter = statisticManager.getCounter(SESSION_READ_COUNTER);
@@ -168,15 +154,10 @@ public class SessionDelegate {
return sessionStats;
}
- private long getThreadSaveCount() {
- Long c = threadSaveCount.get();
- return c == null ? 0 : c;
- }
-
public void refreshAtNextAccess() {
lock.lock();
try {
- refreshAtNextAccess = true;
+ refreshAtNextAccess.refreshAtNextAccess(true);
} finally {
lock.unlock();
}
@@ -222,13 +203,10 @@ public class SessionDelegate {
if (!sessionOperation.isRefresh()
&& !sessionOperation.isSave()
&& !sessionOperation.isLogout()
- && (refreshAtNextAccess
- || sessionSaveCount != getThreadSaveCount()
- || refreshStrategy.needsRefresh(
- SECONDS.convert(t0 - sessionCounters.accessTime,
MILLISECONDS)))) {
+ && refreshStrategy.needsRefresh(
+ SECONDS.convert(t0 - sessionCounters.accessTime,
MILLISECONDS))) {
refresh(true);
- refreshAtNextAccess = false;
- sessionSaveCount = getThreadSaveCount();
+ refreshStrategy.refreshed();
updateCount++;
}
sessionOperation.checkPreconditions();
@@ -255,12 +233,12 @@ public class SessionDelegate {
readDuration.addAndGet(dt);
}
if (sessionOperation.isSave()) {
- refreshAtNextAccess = false;
+ refreshAtNextAccess.refreshAtNextAccess(false);
// Force refreshing on access through other sessions on
the same thread
- threadSaveCount.set(sessionSaveCount =
(getThreadSaveCount() + 1));
+ saveCountRefresh.forceRefresh();
} else if (sessionOperation.isRefresh()) {
- refreshAtNextAccess = false;
- sessionSaveCount = getThreadSaveCount();
+ refreshAtNextAccess.refreshAtNextAccess(false);
+ saveCountRefresh.refreshed();
}
}
} finally {
@@ -766,4 +744,74 @@ public class SessionDelegate {
}
}
+
+ private static class RefreshAtNextAccess implements RefreshStrategy {
+ private boolean refreshAtNextAccess;
+
+ public void refreshAtNextAccess(boolean refreshAtNextAccess) {
+ this.refreshAtNextAccess = refreshAtNextAccess;
+ }
+
+ @Override
+ public boolean needsRefresh(long secondsSinceLastAccess) {
+ return refreshAtNextAccess;
+ }
+
+ @Override
+ public void refreshed() {
+ refreshAtNextAccess = false;
+ }
+
+ @Override
+ public String toString() {
+ return "Refresh on observation event";
+ }
+ }
+
+ private static class SaveCountRefresh implements RefreshStrategy {
+ /**
+ * The repository-wide {@link ThreadLocal} that keeps track of the
number
+ * of saves performed in each thread.
+ */
+ private final ThreadLocal<Long> threadSaveCount;
+
+ /**
+ * Local copy of the {@link #threadSaveCount} for the current thread.
+ * If the repository-wide counter differs from our local copy, then
+ * some other session would have done a commit or this session is
+ * being accessed from some other thread. In either case it's best to
+ * refresh this session to avoid unexpected behaviour.
+ */
+ private long sessionSaveCount;
+
+ public SaveCountRefresh(ThreadLocal<Long> threadSaveCount) {
+ this.threadSaveCount = threadSaveCount;
+ this.sessionSaveCount = getThreadSaveCount();
+ }
+
+ public void forceRefresh() {
+ threadSaveCount.set(sessionSaveCount = (getThreadSaveCount() + 1));
+ }
+
+ @Override
+ public boolean needsRefresh(long secondsSinceLastAccess) {
+ return sessionSaveCount != getThreadSaveCount();
+ }
+
+ @Override
+ public void refreshed() {
+ sessionSaveCount = getThreadSaveCount();
+ }
+
+ private long getThreadSaveCount() {
+ Long c = threadSaveCount.get();
+ return c == null ? 0 : c;
+ }
+
+ @Override
+ public String toString() {
+ return "Refresh after a save on the same thread from a different
session";
+ }
+ }
+
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/repository/RepositoryImpl.java
Wed Mar 4 10:46:46 2015
@@ -274,7 +274,7 @@ public class RepositoryImpl implements J
ContentSession contentSession) {
final RefreshOnGC refreshOnGC = new RefreshOnGC();
- refreshStrategy = new Composite(refreshStrategy, refreshOnGC);
+ refreshStrategy = Composite.create(refreshStrategy, refreshOnGC);
return new SessionDelegate(
contentSession, securityProvider, refreshStrategy,
@@ -470,12 +470,17 @@ public class RepositoryImpl implements J
@Override
public boolean needsRefresh(long secondsSinceLastAccess) {
- if (compacted) {
- compacted = false;
- return true;
- } else {
- return false;
- }
+ return compacted;
+ }
+
+ @Override
+ public void refreshed() {
+ compacted = false;
+ }
+
+ @Override
+ public String toString() {
+ return "Refresh on revision garbage collection";
}
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/RefreshStrategy.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/RefreshStrategy.java?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/RefreshStrategy.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/RefreshStrategy.java
Wed Mar 4 10:46:46 2015
@@ -18,9 +18,13 @@
*/
package org.apache.jackrabbit.oak.jcr.session;
+import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
+import java.util.ArrayList;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,20 +53,34 @@ public interface RefreshStrategy {
*/
boolean needsRefresh(long secondsSinceLastAccess);
+ void refreshed();
+
/**
* Composite of zero or more {@code RefreshStrategy} instances,
* each of which covers a certain strategy.
*/
- public static class Composite implements RefreshStrategy {
+ class Composite implements RefreshStrategy {
private final RefreshStrategy[] refreshStrategies;
+ public static RefreshStrategy create(RefreshStrategy...
refreshStrategies) {
+ ArrayList<RefreshStrategy> strategies = newArrayList();
+ for (RefreshStrategy strategy : refreshStrategies) {
+ if (strategy instanceof Composite) {
+ strategies.addAll(asList(((Composite)
strategy).refreshStrategies));
+ } else {
+ strategies.add(strategy);
+ }
+ }
+ return new Composite(strategies.toArray(new
RefreshStrategy[strategies.size()]));
+ }
+
/**
* Create a new instance consisting of the composite of the
* passed {@code RefreshStrategy} instances.
* @param refreshStrategies individual refresh strategies
*/
- public Composite(RefreshStrategy... refreshStrategies) {
+ private Composite(RefreshStrategy... refreshStrategies) {
this.refreshStrategies = refreshStrategies;
}
@@ -77,6 +95,7 @@ public interface RefreshStrategy {
* @param secondsSinceLastAccess seconds since last access
* @return {@code true} if and only if the session needs to refresh.
*/
+ @Override
public boolean needsRefresh(long secondsSinceLastAccess) {
for (RefreshStrategy r : refreshStrategies) {
if (r.needsRefresh(secondsSinceLastAccess)) {
@@ -86,14 +105,31 @@ public interface RefreshStrategy {
return false;
}
+ @Override
+ public void refreshed() {
+ for (RefreshStrategy refreshStrategy : refreshStrategies) {
+ refreshStrategy.refreshed();
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ String sep = "";
+ for (RefreshStrategy strategy : refreshStrategies) {
+ sb.append(sep).append(strategy.toString());
+ sep = ", ";
+ }
+ return sb.toString();
+ }
}
/**
* This refresh strategy refreshes after a given timeout of inactivity.
*/
- public static class Timed implements RefreshStrategy {
+ class Timed implements RefreshStrategy {
- private final long interval;
+ protected final long interval;
/**
* @param interval Interval in seconds after which a session should
refresh if there was no
@@ -108,6 +144,15 @@ public interface RefreshStrategy {
return secondsSinceLastAccess > interval;
}
+ @Override
+ public void refreshed() {
+ // empty
+ }
+
+ @Override
+ public String toString() {
+ return "Refresh every " + interval + " seconds";
+ }
}
/**
@@ -116,7 +161,7 @@ public interface RefreshStrategy {
*
* TODO replace logging with JMX monitoring. See OAK-941
*/
- public static class LogOnce extends Timed {
+ class LogOnce extends Timed {
private static final Logger log =
LoggerFactory.getLogger(RefreshStrategy.class);
@@ -147,11 +192,19 @@ public interface RefreshStrategy {
+ " minutes and might be out of date. " +
"Consider using a fresh session or explicitly refresh
the session.",
initStackTrace);
- warnIfIdle = false;
}
return false;
}
+ @Override
+ public void refreshed() {
+ warnIfIdle = false;
+ }
+
+ @Override
+ public String toString() {
+ return "Never refresh but log warning after more than " + interval
+ " seconds of inactivity";
+ }
}
}
Modified:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionStats.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionStats.java?rev=1663927&r1=1663926&r2=1663927&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionStats.java
(original)
+++
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionStats.java
Wed Mar 4 10:46:46 2015
@@ -45,13 +45,17 @@ public class SessionStats implements Ses
private final Counters counters;
private final String sessionId;
private final AuthInfo authInfo;
+ private final Clock clock;
+ private final RefreshStrategy refreshStrategy;
private Map<String, Object> attributes = Collections.emptyMap();
- public SessionStats(String sessionId, AuthInfo authInfo, Clock clock) {
+ public SessionStats(String sessionId, AuthInfo authInfo, Clock clock,
RefreshStrategy refreshStrategy) {
this.counters = new Counters(clock);
this.sessionId = sessionId;
this.authInfo = authInfo;
+ this.clock = clock;
+ this.refreshStrategy = refreshStrategy;
}
public static class Counters {
@@ -193,6 +197,17 @@ public class SessionStats implements Ses
}
@Override
+ public String getRefreshStrategy() {
+ return refreshStrategy.toString();
+ }
+
+ @Override
+ public boolean getRefreshPending() {
+ return refreshStrategy.needsRefresh(
+ SECONDS.convert(clock.getTime() - counters.accessTime,
MILLISECONDS));
+ }
+
+ @Override
public long getRefreshCount() {
return counters.getRefreshCount();
}