You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2011/09/08 22:33:57 UTC

svn commit: r1166889 - in /tapestry/tapestry5/trunk/tapestry-core/src: main/java/org/apache/tapestry5/ main/java/org/apache/tapestry5/internal/services/ main/java/org/apache/tapestry5/services/ test/java/org/apache/tapestry5/integration/app1/services/

Author: hlship
Date: Thu Sep  8 20:33:57 2011
New Revision: 1166889

URL: http://svn.apache.org/viewvc?rev=1166889&view=rev
Log:
TAP5-1637: Use SoftReferences to cache Page instances, rather than an explicit janitor job

Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
    tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java?rev=1166889&r1=1166888&r2=1166889&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/SymbolConstants.java Thu Sep  8 20:33:57 2011
@@ -313,23 +313,6 @@ public class SymbolConstants
     public static final String CLUSTERED_SESSIONS = "tapestry.clustered-sessions";
 
     /**
-     * The interval (in milliseconds) at which the {@link org.apache.tapestry5.internal.services.PageSource} checks for
-     * inactive pages that can be discarded. The default is "5 m" (every five minutes).
-     *
-     * @since 5.3
-     */
-    public static final String PAGE_SOURCE_CHECK_INTERVAL = "tapestry.page-source-check-interval";
-
-    /**
-     * The maximum amount of time, in milliseconds, that an instantiated page instance may be kept in memory
-     * before being discarded. The frequency of checks for such pages is determined by {@link #PAGE_SOURCE_CHECK_INTERVAL}.
-     * The default is "15 m" (fifteen minutes).
-     *
-     * @since 5.3
-     */
-    public static final String PAGE_SOURCE_ACTIVE_WINDOW = "tapestry.page-source-active-window";
-
-    /**
      * The fix for <a href="https://issues.apache.org/jira/browse/TAP5-1596">TAP5-1596</a> means that component ids referenced
      * by event handler methods (either the naming convention, or the {@link org.apache.tapestry5.annotations.OnEvent} annotation)
      * can cause a page load error if there is no matching component in the component's template. Although this is correct behavior,

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java?rev=1166889&r1=1166888&r2=1166889&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageSourceImpl.java Thu Sep  8 20:33:57 2011
@@ -14,22 +14,13 @@
 
 package org.apache.tapestry5.internal.services;
 
-import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.structure.Page;
-import org.apache.tapestry5.ioc.annotations.IntermediateType;
-import org.apache.tapestry5.ioc.annotations.PostInjection;
-import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
-import org.apache.tapestry5.ioc.services.cron.IntervalSchedule;
-import org.apache.tapestry5.ioc.services.cron.PeriodicExecutor;
-import org.apache.tapestry5.ioc.util.TimeInterval;
 import org.apache.tapestry5.services.InvalidationListener;
 import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
-import org.slf4j.Logger;
 
-import java.util.Date;
-import java.util.Iterator;
+import java.lang.ref.SoftReference;
 import java.util.Map;
 
 public class PageSourceImpl implements PageSource, InvalidationListener
@@ -38,10 +29,6 @@ public class PageSourceImpl implements P
 
     private final PageLoader pageLoader;
 
-    private final long activeWindow;
-
-    private final Logger logger;
-
     private static final class CachedPageKey
     {
         final String pageName;
@@ -73,91 +60,50 @@ public class PageSourceImpl implements P
         }
     }
 
-    private final Map<CachedPageKey, Page> pageCache = CollectionFactory.newConcurrentMap();
+    private final Map<CachedPageKey, SoftReference<Page>> pageCache = CollectionFactory.newConcurrentMap();
 
-    public PageSourceImpl(PageLoader pageLoader, ComponentRequestSelectorAnalyzer selectorAnalyzer,
-
-                          @Symbol(SymbolConstants.PAGE_SOURCE_ACTIVE_WINDOW)
-                          @IntermediateType(TimeInterval.class)
-                          long activeWindow, Logger logger)
+    public PageSourceImpl(PageLoader pageLoader, ComponentRequestSelectorAnalyzer selectorAnalyzer)
     {
         this.pageLoader = pageLoader;
         this.selectorAnalyzer = selectorAnalyzer;
-        this.activeWindow = activeWindow;
-        this.logger = logger;
     }
 
-    @PostInjection
-    public void startJanitor(PeriodicExecutor executor, @Symbol(SymbolConstants.PAGE_SOURCE_CHECK_INTERVAL)
-    @IntermediateType(TimeInterval.class)
-    long checkInterval)
+    public void objectWasInvalidated()
     {
-        executor.addJob(new IntervalSchedule(checkInterval), "PagePool cleanup", new Runnable()
-        {
-            public void run()
-            {
-                prune();
-            }
-        });
+        clearCache();
     }
 
-    private void prune()
+    public Page getPage(String canonicalPageName)
     {
-        Iterator<Page> iterator = pageCache.values().iterator();
+        ComponentResourceSelector selector = selectorAnalyzer.buildSelectorForRequest();
 
-        int count = 0;
+        CachedPageKey key = new CachedPageKey(canonicalPageName, selector);
 
-        long cutoff = System.currentTimeMillis() - activeWindow;
+        // The while loop looks superfluous, but it helps to ensure that the Page instance,
+        // with all of its mutable construction-time state, is properly published to other
+        // threads (at least, as I understand Brian Goetz's explanation, it should be).
 
-        while (iterator.hasNext())
+        while (true)
         {
-            Page page = iterator.next();
+            SoftReference<Page> ref = pageCache.get(key);
 
-            if (page.getLastAttachTime() <= cutoff)
-            {
-                count++;
-                iterator.remove();
+            Page page = ref == null ? null : ref.get();
 
-                logger.info(String.format("Pruned page %s (%s), not accessed since %s.",
-                        page.getName(),
-                        page.getSelector().toShortString(),
-                        new Date(page.getLastAttachTime())));
+            if (page != null)
+            {
+                return page;
             }
-        }
-
-        if (count > 0)
-        {
-            logger.info(String.format("Pruned %d page %s.", count, count == 1 ? "instance" : "instances"));
-        }
-    }
-
-    public synchronized void objectWasInvalidated()
-    {
-        pageCache.clear();
-    }
 
-    public Page getPage(String canonicalPageName)
-    {
-        ComponentResourceSelector selector = selectorAnalyzer.buildSelectorForRequest();
-
-        CachedPageKey key = new CachedPageKey(canonicalPageName, selector);
-
-        if (!pageCache.containsKey(key))
-        {
             // In rare race conditions, we may see the same page loaded multiple times across
             // different threads. The last built one will "evict" the others from the page cache,
             // and the earlier ones will be GCed.
 
-            Page page = pageLoader.loadPage(canonicalPageName, selector);
+            page = pageLoader.loadPage(canonicalPageName, selector);
 
-            pageCache.put(key, page);
-        }
-
-        // From good authority (Brian Goetz), this is the best way to ensure that the
-        // loaded page, with all of its semi-mutable construction-time state, is
-        // properly published.
+            ref = new SoftReference<Page>(page);
 
-        return pageCache.get(key);
+            pageCache.put(key, ref);
+        }
     }
 
     public void clearCache()

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=1166889&r1=1166888&r2=1166889&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java Thu Sep  8 20:33:57 2011
@@ -2369,9 +2369,6 @@ public final class TapestryModule
         configuration.add(SymbolConstants.HOSTPORT, 0);
         configuration.add(SymbolConstants.HOSTPORT_SECURE, 0);
 
-        configuration.add(SymbolConstants.PAGE_SOURCE_CHECK_INTERVAL, "5 m");
-        configuration.add(SymbolConstants.PAGE_SOURCE_ACTIVE_WINDOW, "15 m");
-
         configuration.add(SymbolConstants.UNKNOWN_COMPONENT_ID_CHECK_ENABLED, true);
 
         configuration.add(SymbolConstants.APPLICATION_FOLDER, "");

Modified: tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java?rev=1166889&r1=1166888&r2=1166889&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/services/AppModule.java Thu Sep  8 20:33:57 2011
@@ -142,9 +142,6 @@ public class AppModule
         configuration.add(SymbolConstants.SECURE_ENABLED, "true");
 
         configuration.add("app.injected-symbol", "Symbol contributed to ApplicationDefaults");
-
-        configuration.add(SymbolConstants.PAGE_SOURCE_ACTIVE_WINDOW, "30s");
-        configuration.add(SymbolConstants.PAGE_SOURCE_CHECK_INTERVAL, "15s");
     }
 
     public static void contributeIgnoredPathsFilter(Configuration<String> configuration)