roller-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agillil...@apache.org
Subject svn commit: r349478 [2/2] - in /incubator/roller/trunk: src/org/roller/presentation/ src/org/roller/presentation/cache/ src/org/roller/presentation/filters/ src/org/roller/presentation/pagecache/ src/org/roller/presentation/pagecache/rollercache/ src/o...
Date Mon, 28 Nov 2005 19:44:39 GMT
Added: incubator/roller/trunk/src/org/roller/presentation/filters/WeblogPageCacheFilter.java
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/filters/WeblogPageCacheFilter.java?rev=349478&view=auto
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/filters/WeblogPageCacheFilter.java
(added)
+++ incubator/roller/trunk/src/org/roller/presentation/filters/WeblogPageCacheFilter.java
Mon Nov 28 11:44:28 2005
@@ -0,0 +1,396 @@
+/*
+ * WeblogPageCacheFilter.java
+ *
+ * Created on October 27, 2005, 12:19 PM
+ */
+package org.roller.presentation.filters;
+
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.roller.config.RollerConfig;
+import org.roller.pojos.BookmarkData;
+import org.roller.pojos.CommentData;
+import org.roller.pojos.FolderData;
+import org.roller.pojos.RefererData;
+import org.roller.pojos.UserData;
+import org.roller.pojos.WeblogCategoryData;
+import org.roller.pojos.WeblogEntryData;
+import org.roller.pojos.WeblogTemplate;
+import org.roller.pojos.WebsiteData;
+import org.roller.presentation.WeblogPageRequest;
+import org.roller.presentation.cache.Cache;
+import org.roller.presentation.cache.CacheHandler;
+import org.roller.presentation.cache.CacheManager;
+import org.roller.presentation.util.CacheHttpServletResponseWrapper;
+import org.roller.presentation.util.ResponseContent;
+
+/**
+ * A filter used for caching fully rendered weblog pages ... /page/*
+ *
+ * @web.filter name="WeblogPageCacheFilter"
+ *
+ * @author  Allen Gilliland
+ */
+public class WeblogPageCacheFilter implements Filter, CacheHandler {
+    
+    private static Log mLogger =
+            LogFactory.getFactory().getInstance(WeblogPageCacheFilter.class);
+    
+    private boolean excludeOwnerPages = false;
+    private Cache mPageCache = null;
+    
+    // for metrics
+    private double hits = 0;
+    private double misses = 0;
+    private double purges = 0;
+    private Date startTime = new Date();
+    
+    
+    /**
+     * Process filter.
+     */
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+            throws IOException, ServletException {
+        
+        mLogger.debug("entering");
+        
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) res;
+        
+        WeblogPageRequest pageRequest = null;
+        try {
+            pageRequest = new WeblogPageRequest(request);
+        } catch(Exception e) {
+            // some kind of error parsing the request
+            mLogger.error("error creating page request", e);
+            response.sendError(HttpServletResponse.SC_NOT_FOUND);
+            return;
+        }
+        
+        String key = "pageCache:"+this.generateKey(pageRequest);
+        
+        ResponseContent respContent = null;
+        if(!this.excludeOwnerPages || !pageRequest.isLoggedIn()) {
+            respContent = (ResponseContent) this.mPageCache.get(key);
+        }
+        
+        if (respContent == null) {
+            
+            mLogger.debug("MISS "+key);
+            this.misses++;
+            
+            try {
+                CacheHttpServletResponseWrapper cacheResponse =
+                        new CacheHttpServletResponseWrapper(response);
+                
+                chain.doFilter(request, cacheResponse);
+                
+                cacheResponse.flushBuffer();
+                
+                // Store as the cache content the result of the response
+                // if no exception was noted by content generator.
+                if (request.getAttribute("DisplayException") == null) {
+                    ResponseContent rc = cacheResponse.getContent();
+                    
+                    // only cache if this is not a logged in user?
+                    if(!this.excludeOwnerPages || !pageRequest.isLoggedIn()) {
+                        this.mPageCache.put(key, rc);
+                    } else {
+                        mLogger.debug("SKIPPED "+key);
+                    }
+                } else {
+                    mLogger.error("Display exception "+key);
+                }
+                
+            } catch (java.net.SocketException se) {
+                // ignored
+            } catch (Exception e) {
+                // something unexpected and bad happened
+                mLogger.error("Error rendering page "+key, e);
+            }
+            
+        } else {
+            
+            mLogger.debug("HIT "+key);
+            this.hits++;
+            
+            try {
+                respContent.writeTo(response);
+            } catch (java.net.SocketException se) {
+                // ignored
+            } catch (Exception e) {
+                mLogger.error("Error with cached response "+key, e);
+            }
+            
+        }
+        
+        mLogger.debug("exiting");
+    }
+    
+    
+    /**
+     * Generate a cache key from a parsed weblog page request.
+     * This generates a key of the form ...
+     *
+     * weblog/<handle>/page/<type>[/anchor]/<weblogPage>/<language>[/user]
+     *   or
+     * weblog/<handle>/page/<type>[/date][/category]/<weblogPage>/<language>[/user]
+     *
+     *
+     * examples ...
+     *
+     * weblog/foo/page/main/Weblog/en
+     * weblog/foo/page/permalink/entry_anchor/Weblog/en
+     * weblog/foo/page/archive/20051110/Weblog/en
+     * weblog/foo/page/archive/MyCategory/Weblog/en/user=myname
+     *
+     */
+    private String generateKey(WeblogPageRequest pageRequest) {
+        
+        StringBuffer key = new StringBuffer();
+        key.append("weblog/");
+        key.append(pageRequest.getWeblogHandle());
+        key.append("/page/");
+        key.append(pageRequest.getPageType());
+        
+        if(pageRequest.getWeblogAnchor() != null) {
+            // TODO: do we need to convert to base64 here?
+            // this.weblogAnchor = Utilities.toBase64(this.weblogAnchor.getBytes());
+            key.append("/").append(pageRequest.getWeblogAnchor());
+        } else {
+            
+            if(pageRequest.getWeblogDate() != null) {
+                key.append("/").append(pageRequest.getWeblogDate());
+            }
+            
+            if(pageRequest.getWeblogCategory() != null) {
+                String cat = pageRequest.getWeblogCategory();
+                if(cat.startsWith("/")) {
+                    cat = cat.substring(1);
+                }
+
+                key.append("/").append(cat);
+            }
+        }
+        
+        // add page name
+        key.append("/").append(pageRequest.getWeblogPage());
+        
+        // add language
+        key.append("/").append(pageRequest.getLanguage());
+        
+        // add login state
+        if(pageRequest.getAuthenticUser() != null) {
+            key.append("/user=").append(pageRequest.getAuthenticUser());
+        }
+        
+        return key.toString();
+    }
+    
+    
+    /**
+     * A weblog entry has changed.
+     */
+    public void invalidate(WeblogEntryData entry) {
+        
+        mLogger.debug("invalidating entry = "+entry.getAnchor());
+        
+        // we need to remove the following cached items if they exist
+        //   - the weblog main page
+        //   - the weblog entry permalink page
+        //   - the weblog archive pages
+        
+        String handle = entry.getWebsite().getHandle();
+        String keyBase = "pageCache:weblog/"+handle+"/page";
+        
+        Set removeSet = new HashSet();
+        
+        // TODO: it would be nice to be able to do this without iterating 
+        //       over the entire cache key set
+        String key = null;
+        Iterator allKeys = this.mPageCache.keySet().iterator();
+        while(allKeys.hasNext()) {
+            key = (String) allKeys.next();
+            if(key.startsWith(keyBase+"/main")) {
+                removeSet.add(key);
+            } else if(key.startsWith(keyBase+"/archive")) {
+                // at some point it would be cool to actually calculate what
+                // archive pages to remove in specific, rather than all of 'em
+                removeSet.add(key);
+            } else if(key.startsWith(keyBase+"/permalink/"+entry.getAnchor())) {
+                removeSet.add(key);
+            }
+        }
+        
+        this.mPageCache.remove(removeSet);
+    }
+    
+    
+    /**
+     * A weblog has changed.
+     */
+    public void invalidate(WebsiteData website) {
+        
+        mLogger.debug("invalidating website = "+website.getHandle());
+        
+        // we need to remove the following cached items if they exist
+        //   - all pages for this weblog
+        
+        Set removeSet = new HashSet();
+        
+        // TODO: it would be nice to be able to do this without iterating 
+        //       over the entire cache key set
+        String key = null;
+        Iterator allKeys = this.mPageCache.keySet().iterator();
+        while(allKeys.hasNext()) {
+            key = (String) allKeys.next();
+            
+            if(key.startsWith("pageCache:weblog/"+website.getHandle())) {
+                removeSet.add(key);
+            }
+        }
+        
+        this.mPageCache.remove(removeSet);
+    }
+    
+    
+    /**
+     * A bookmark has changed.
+     */
+    public void invalidate(BookmarkData bookmark) {
+        this.invalidate(bookmark.getWebsite());
+    }
+    
+    
+    /**
+     * A folder has changed.
+     */
+    public void invalidate(FolderData folder) {
+        this.invalidate(folder.getWebsite());
+    }
+    
+    
+    /**
+     * A comment has changed.
+     */
+    public void invalidate(CommentData comment) {
+        this.invalidate(comment.getWeblogEntry());
+    }
+    
+    
+    /**
+     * A referer has changed.
+     */
+    public void invalidate(RefererData referer) {
+        // ignored
+        // TODO: we probably should invalidate the entire website?
+    }
+    
+    
+    /**
+     * A user profile has changed.
+     */
+    public void invalidate(UserData user) {
+        // ignored
+        // TODO: i don't think weblog pages currently reference user objects
+    }
+    
+    
+    /**
+     * A category has changed.
+     */
+    public void invalidate(WeblogCategoryData category) {
+        this.invalidate(category.getWebsite());
+    }
+    
+    
+    /**
+     * A weblog template has changed.
+     */
+    public void invalidate(WeblogTemplate template) {
+        this.invalidate(template.getWebsite());
+    }
+    
+    
+    public Map getStats() {
+        
+        Map stats = new HashMap();
+        stats.put("startTime", this.startTime);
+        stats.put("hits", new Double(this.hits));
+        stats.put("misses", new Double(this.misses));
+        stats.put("purges", new Double(this.purges));
+        
+        // calculate efficiency
+        if((misses - purges) > 0) {
+            double efficiency = hits / (misses + hits);
+            stats.put("efficiency", new Double(efficiency * 100));
+        }
+        
+        return stats;
+    }
+    
+    
+    /**
+     * Destroy method for this filter
+     */
+    public void destroy() {
+    }
+    
+    
+    /**
+     * Init method for this filter
+     */
+    public void init(FilterConfig filterConfig) {
+        
+        mLogger.info("Initializing weblog page cache");
+        
+        String factory = RollerConfig.getProperty("cache.weblogpage.factory");
+        String size = RollerConfig.getProperty("cache.weblogpage.size");
+        String timeout = RollerConfig.getProperty("cache.weblogpage.timeout");
+        this.excludeOwnerPages = 
+                RollerConfig.getBooleanProperty("cache.weblogpage.excludeOwnerEditPages");
+        
+        int cacheSize = 100;
+        try {
+            cacheSize = Integer.parseInt(size);
+        } catch (Exception e) {
+            mLogger.warn("Invalid page cache size ["+size+"], using default");
+        }
+        
+        long cacheTimeout = 30 * 60;
+        try {
+            cacheTimeout = Long.parseLong(timeout);
+        } catch (Exception e) {
+            mLogger.warn("Invalid page cache timeout ["+timeout+
+                    "], using default");
+        }
+        
+        
+        Map props = new HashMap();
+        props.put("timeout", ""+cacheTimeout);
+        props.put("size", ""+cacheSize);
+        
+        if(factory != null && factory.trim().length() > 0)
+            props.put("cache.factory", factory);
+        
+        mLogger.info(props);
+        
+        mPageCache = CacheManager.constructCache(this, props);
+    }
+    
+}

Copied: incubator/roller/trunk/src/org/roller/presentation/util/CacheHttpServletResponseWrapper.java
(from r349452, incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/CacheHttpServletResponseWrapper.java)
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/util/CacheHttpServletResponseWrapper.java?p2=incubator/roller/trunk/src/org/roller/presentation/util/CacheHttpServletResponseWrapper.java&p1=incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/CacheHttpServletResponseWrapper.java&r1=349452&r2=349478&rev=349478&view=diff
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/CacheHttpServletResponseWrapper.java
(original)
+++ incubator/roller/trunk/src/org/roller/presentation/util/CacheHttpServletResponseWrapper.java
Mon Nov 28 11:44:28 2005
@@ -2,17 +2,14 @@
  * Copyright (c) 2002-2003 by OpenSymphony
  * All rights reserved.
  */
-package org.roller.presentation.pagecache.rollercache;
+package org.roller.presentation.util;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-
 import java.util.Locale;
-
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;

Copied: incubator/roller/trunk/src/org/roller/presentation/util/ResponseContent.java (from
r349452, incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java)
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/util/ResponseContent.java?p2=incubator/roller/trunk/src/org/roller/presentation/util/ResponseContent.java&p1=incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java&r1=349452&r2=349478&rev=349478&view=diff
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/ResponseContent.java
(original)
+++ incubator/roller/trunk/src/org/roller/presentation/util/ResponseContent.java Mon Nov 28
11:44:28 2005
@@ -2,7 +2,7 @@
  * Copyright (c) 2002-2003 by OpenSymphony
  * All rights reserved.
  */
-package org.roller.presentation.pagecache.rollercache;
+package org.roller.presentation.util;
 
 import java.io.*;
 

Copied: incubator/roller/trunk/src/org/roller/presentation/util/SplitPrintWriter.java (from
r349452, incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java)
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/util/SplitPrintWriter.java?p2=incubator/roller/trunk/src/org/roller/presentation/util/SplitPrintWriter.java&p1=incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java&r1=349452&r2=349478&rev=349478&view=diff
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitPrintWriter.java
(original)
+++ incubator/roller/trunk/src/org/roller/presentation/util/SplitPrintWriter.java Mon Nov
28 11:44:28 2005
@@ -1,4 +1,4 @@
-package org.roller.presentation.pagecache.rollercache;
+package org.roller.presentation.util;
 
 import java.io.PrintWriter;
 import java.io.Writer;

Copied: incubator/roller/trunk/src/org/roller/presentation/util/SplitServletOutputStream.java
(from r349452, incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java)
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/src/org/roller/presentation/util/SplitServletOutputStream.java?p2=incubator/roller/trunk/src/org/roller/presentation/util/SplitServletOutputStream.java&p1=incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java&r1=349452&r2=349478&rev=349478&view=diff
==============================================================================
--- incubator/roller/trunk/src/org/roller/presentation/pagecache/rollercache/SplitServletOutputStream.java
(original)
+++ incubator/roller/trunk/src/org/roller/presentation/util/SplitServletOutputStream.java
Mon Nov 28 11:44:28 2005
@@ -2,7 +2,7 @@
  * Copyright (c) 2002-2003 by OpenSymphony
  * All rights reserved.
  */
-package org.roller.presentation.pagecache.rollercache;
+package org.roller.presentation.util;
 
 import java.io.IOException;
 import java.io.OutputStream;

Modified: incubator/roller/trunk/web/WEB-INF/classes/roller.properties
URL: http://svn.apache.org/viewcvs/incubator/roller/trunk/web/WEB-INF/classes/roller.properties?rev=349478&r1=349477&r2=349478&view=diff
==============================================================================
--- incubator/roller/trunk/web/WEB-INF/classes/roller.properties (original)
+++ incubator/roller/trunk/web/WEB-INF/classes/roller.properties Mon Nov 28 11:44:28 2005
@@ -56,20 +56,41 @@
 search.index.dir=${user.home}/roller_data/search-index
 
 #----------------------------------
-# Cache settings, remember ... times are in seconds
+# Cache settings.
+# Remember ... times are in seconds
 # Default settings suitable for 100 user system
 
-# Number of RSS feeds to cache (and timeout)
-cache.filter.rss.size=100
-cache.filter.rss.timeout=3600
-
-# Number of if-modified dates to cache (and timeout)
-cache.filter.ifmodified.size=100
-cache.filter.ifmodified.timeout=1800
-
-# number of blog pages to cache (and timeout)
-cache.filter.page.size=100
-cache.filter.page.timeout=3600
+# The default cache implementation we want to use
+cache.factory.classname=org.roller.presentation.cache.ExpiringLRUCacheFactoryImpl
+cache.customHandlers=
+
+
+# Main/Planet page cache (this is low on purpose)
+cache.mainpage.size=10
+cache.mainpage.timeout=1800
+# set "true" to NOT cache the custom pages for users who are logged in
+cache.mainpage.excludeOwnerEditPages=false
+
+# Weblog page cache (all the weblog content)
+cache.weblogpage.size=400
+cache.weblogpage.timeout=3600
+# set "true" to NOT cache the custom pages for users who are logged in
+cache.weblogpage.excludeOwnerEditPages=false
+
+# Weblog page last-modified-date cache 
+# you want this fairly high, like weblogs * 10, with long timeouts
+cache.weblogpage.ifmodified.size=1000
+cache.weblogpage.ifmodified.timeout=14400
+
+
+# Feed cache (xml feeds like rss, atom, etc)
+cache.feed.size=200
+cache.feed.timeout=3600
+
+# Feed last-modified-date cache
+# you want a reasonable size, like weblogs * 2, with long timeouts
+cache.feed.ifmodified.size=200
+cache.feed.ifmodified.timeout=14400
 
 #----------------------------------
 # Secure login configs



Mime
View raw message