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();
     }


Reply via email to