jackrabbit-oak-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mdue...@apache.org
Subject svn commit: r1517759 - in /jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr: RepositoryImpl.java delegate/RefreshManager.java delegate/SessionDelegate.java
Date Tue, 27 Aug 2013 08:13:24 GMT
Author: mduerig
Date: Tue Aug 27 08:13:23 2013
New Revision: 1517759

URL: http://svn.apache.org/r1517759
Log:
OAK-960: Enable session refresh state coordination between multiple session in single thread
Factor refresh logic into its own RefreshManager class

Added:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
  (with props)
Modified:
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java?rev=1517759&r1=1517758&r2=1517759&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
(original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/RepositoryImpl.java
Tue Aug 27 08:13:23 2013
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.oak.jcr;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import java.util.Collections;
 import java.util.Map;
@@ -37,6 +39,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.commons.SimpleValueFactory;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.jcr.delegate.RefreshManager;
 import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
 import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
@@ -57,7 +60,7 @@ public class RepositoryImpl implements J
      * Name of the session attribute value determining the session refresh
      * behaviour.
      *
-     * @see SessionDelegate#SessionDelegate(ContentSession, SecurityProvider, long)
+     * @see SessionDelegate#SessionDelegate(ContentSession, RefreshManager, SecurityProvider)
      */
     public static final String REFRESH_INTERVAL = "oak.refresh-interval";
 
@@ -70,6 +73,7 @@ public class RepositoryImpl implements J
     private final ContentRepository contentRepository;
     protected final Whiteboard whiteboard;
     private final SecurityProvider securityProvider;
+    private final ThreadLocal<Integer> threadSafeCount;
 
     public RepositoryImpl(@Nonnull ContentRepository contentRepository,
                           @Nonnull Whiteboard whiteboard,
@@ -77,6 +81,7 @@ public class RepositoryImpl implements J
         this.contentRepository = checkNotNull(contentRepository);
         this.whiteboard = checkNotNull(whiteboard);
         this.securityProvider = checkNotNull(securityProvider);
+        this.threadSafeCount = new ThreadLocal<Integer>();
     }
 
     //---------------------------------------------------------< Repository >---
@@ -203,17 +208,19 @@ public class RepositoryImpl implements J
             }
 
             ContentSession contentSession = contentRepository.login(credentials, workspaceName);
+            RefreshManager refreshManager = new RefreshManager(
+                    MILLISECONDS.convert(refreshInterval, SECONDS), threadSafeCount);
+            SessionDelegate sessionDelegate = new SessionDelegate(
+                    contentSession, refreshManager, securityProvider);
             SessionContext context = createSessionContext(
                     Collections.<String, Object>singletonMap(REFRESH_INTERVAL, refreshInterval),
-                    new SessionDelegate(contentSession,securityProvider,refreshInterval));
+                    sessionDelegate);
             return context.getSession();
         } catch (LoginException e) {
             throw new javax.jcr.LoginException(e.getMessage(), e);
         }
     }
 
-
-
     @Override
     public void shutdown() {
         // empty

Added: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java?rev=1517759&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
(added)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
Tue Aug 27 08:13:23 2013
@@ -0,0 +1,104 @@
+/*
+ * 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.jcr.delegate;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
+import org.apache.jackrabbit.oak.jcr.operation.SessionOperation;
+
+/**
+* michid document
+*/
+public class RefreshManager {
+    private final Exception initStackTrace = new Exception("The session was created here:");
+    private final long refreshInterval;
+
+    /**
+     * ThreadLocal instance to keep track of the save operations performed in the thread
so far
+     * This is is then used to determine if the current session needs to be refreshed to
see the
+     * changes done by another session in current thread.
+     * <p>
+     * <b>Note</b> - This thread local is never cleared. However, we only store
+     * java.lang.Integer and do not derive from ThreadLocal such that (class loader)
+     * leaks typically associated with thread locals do not occur.
+     */
+    private final ThreadLocal<Integer> threadSaveCount;
+
+    private long lastAccessed = System.currentTimeMillis();
+    private boolean warnIfIdle = true;
+    private boolean refreshAtNextAccess;
+    private int sessionSaveCount;
+
+    public RefreshManager(long refreshInterval, ThreadLocal<Integer> threadSaveCount)
{
+        this.refreshInterval = refreshInterval;
+        this.threadSaveCount = threadSaveCount;
+
+        sessionSaveCount = getOr0(threadSaveCount);
+    }
+
+    boolean refreshIfNecessary(SessionDelegate delegate, SessionOperation<?> sessionOperation)
{
+        long now = System.currentTimeMillis();
+        long timeElapsed = now - lastAccessed;
+        lastAccessed = now;
+
+        // Don't refresh if this operation is a refresh operation itself or
+        // a save operation, which does an implicit refresh
+        if (!sessionOperation.isRefresh() && !sessionOperation.isSave()) {
+            if (warnIfIdle && !refreshAtNextAccess
+                    && timeElapsed > MILLISECONDS.convert(1, MINUTES)) {
+                // Warn once if this session has been idle too long
+                SessionDelegate.log.warn("This session has been idle for " + MINUTES.convert(timeElapsed,
MILLISECONDS) +
+                        " minutes and might be out of date. Consider using a fresh session
or explicitly" +
+                        " refresh the session.", initStackTrace);
+                warnIfIdle = false;
+            }
+            if (refreshAtNextAccess || hasInThreadCommit() || timeElapsed >= refreshInterval)
{
+                // Refresh if forced or if the session has been idle too long
+                refreshAtNextAccess = false;
+                sessionSaveCount = getOr0(threadSaveCount);
+                delegate.refresh(true);
+                return true;
+            }
+        }
+
+        if (sessionOperation.isSave()) {
+            threadSaveCount.set(sessionSaveCount = (getOr0(threadSaveCount) + 1));
+        }
+
+        return false;
+    }
+
+    void refreshAtNextAccess() {
+        refreshAtNextAccess = true;
+    }
+
+    private boolean hasInThreadCommit() {
+        // If the threadLocal counter differs from our seen sessionSaveCount so far then
+        // some other session would have done a commit. If that is the case a refresh would
+        // be required
+        return getOr0(threadSaveCount) != sessionSaveCount;
+    }
+
+    private static int getOr0(ThreadLocal<Integer> threadLocal) {
+        Integer c = threadLocal.get();
+        return c == null ? 0 : c;
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/RefreshManager.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

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=1517759&r1=1517758&r2=1517759&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
Tue Aug 27 08:13:23 2013
@@ -17,9 +17,6 @@
 package org.apache.jackrabbit.oak.jcr.delegate;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.MINUTES;
-import static java.util.concurrent.TimeUnit.SECONDS;
 
 import java.io.IOException;
 
@@ -53,40 +50,17 @@ import org.slf4j.LoggerFactory;
 public class SessionDelegate {
     static final Logger log = LoggerFactory.getLogger(SessionDelegate.class);
 
-    /**
-     * Threadlocal instance to keep track of the save operations performed in the thread
so far
-     * This is is then used to determine if the current session needs to be refreshed to
see the
-     * changes done by another session in current thread.
-     *
-     * <p><b>Note</b> - This thread local is never cleared. However we
are only storing java.lang.Integer
-     * in it thus it would not cause leaks typically associated with usage of thread locals
which are not
-     * cleared
-     * </p>
-     */
-    private static final ThreadLocal<Integer> SAVE_COUNT = new ThreadLocal<Integer>()
{
-        @Override
-        protected Integer initialValue() {
-            return 0;
-        }
-    };
-
     private final ContentSession contentSession;
-    private final long refreshInterval;
+    private final RefreshManager refreshManager;
+
     private final Root root;
     private final IdentifierManager idManager;
-    private final Exception initStackTrace;
     private final PermissionProvider permissionProvider;
 
     private boolean isAlive = true;
     private int sessionOpCount;
     private long updateCount = 0;
 
-    private long lastAccessed = System.currentTimeMillis();
-    private boolean warnIfIdle = true;
-    private boolean refreshAtNextAccess = false;
-
-    private int saveCount = SAVE_COUNT.get();
-
     /**
      * Create a new session delegate for a {@code ContentSession}. The refresh behaviour
of the
      * session is governed by the value of the {@code refreshInterval} argument: if the session
@@ -96,22 +70,22 @@ public class SessionDelegate {
      * dispatcher in order.
      *
      * @param contentSession  the content session
+     * @param refreshManager  the refresh manager used to handle auto refreshing this session
      * @param securityProvider the security provider
-     * @param refreshInterval  refresh interval in seconds.
      */
-    public SessionDelegate(@Nonnull ContentSession contentSession, SecurityProvider securityProvider,long
refreshInterval) {
+    public SessionDelegate(@Nonnull ContentSession contentSession, RefreshManager refreshManager,
+            SecurityProvider securityProvider) {
         this.contentSession = checkNotNull(contentSession);
-        this.refreshInterval = MILLISECONDS.convert(refreshInterval, SECONDS);
+        this.refreshManager = checkNotNull(refreshManager);
         this.root = contentSession.getLatestRoot();
         this.idManager = new IdentifierManager(root);
-        this.initStackTrace = new Exception("The session was created here:");
-        this.permissionProvider = securityProvider.getConfiguration(AuthorizationConfiguration.class)
+        this.permissionProvider = checkNotNull(securityProvider)
+                .getConfiguration(AuthorizationConfiguration.class)
                 .getPermissionProvider(root, contentSession.getAuthInfo().getPrincipals());
-
     }
 
     public synchronized void refreshAtNextAccess() {
-        refreshAtNextAccess = true;
+        refreshManager.refreshAtNextAccess();
     }
 
     /**
@@ -130,28 +104,10 @@ public class SessionDelegate {
             throws RepositoryException {
         // Synchronize to avoid conflicting refreshes from concurrent JCR API calls
         if (sessionOpCount == 0) {
-            // Refresh and checks only for non re-entrant session operations
-            long now = System.currentTimeMillis();
-            long timeElapsed = now - lastAccessed;
-            // Don't refresh if this operation is a refresh operation itself
-            if (!sessionOperation.isRefresh()) {
-                if (warnIfIdle && !refreshAtNextAccess
-                        && timeElapsed > MILLISECONDS.convert(1, MINUTES)) {
-                    // Warn once if this session has been idle too long
-                    log.warn("This session has been idle for " + MINUTES.convert(timeElapsed,
MILLISECONDS) +
-                            " minutes and might be out of date. Consider using a fresh session
or explicitly" +
-                            " refresh the session.", initStackTrace);
-                    warnIfIdle = false;
-                }
-                if (refreshAtNextAccess || commitDoneByOtherSessionInCurrentThread() || timeElapsed
>= refreshInterval) {
-                    // Refresh if forced or if the session has been idle too long
-                    refreshAtNextAccess = false;
-                    saveCount = SAVE_COUNT.get();
-                    refresh(true);
-                    updateCount++;
-                }
+            // Refresh and precondition checks only for non re-entrant session operations
+            if (refreshManager.refreshIfNecessary(this, sessionOperation)) {
+                updateCount++;
             }
-            lastAccessed = now;
             sessionOperation.checkPreconditions();
         }
         try {
@@ -162,9 +118,6 @@ public class SessionDelegate {
             if (sessionOperation.isUpdate()) {
                 updateCount++;
             }
-            if (sessionOperation.isSave()) {
-                SAVE_COUNT.set(saveCount = (SAVE_COUNT.get() + 1));
-            }
         }
     }
 
@@ -460,15 +413,7 @@ public class SessionDelegate {
         return contentSession.toString();
     }
 
-//-----------------------------------------------------------< internal >---
-
-    private boolean commitDoneByOtherSessionInCurrentThread() {
-        //if the threadLocal counter differs from our seen saveCount so far then
-        //some other session would have done a commit. If that is the case a refresh would
-        //be required
-        return SAVE_COUNT.get() != saveCount;
-    }
-
+    //------------------------------------------------------------< internal >---
 
     /**
      * Wraps the given {@link CommitFailedException} instance using the



Mime
View raw message