Return-Path: X-Original-To: apmail-tomcat-dev-archive@www.apache.org Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id BCE9996A5 for ; Fri, 28 Sep 2012 08:41:29 +0000 (UTC) Received: (qmail 99297 invoked by uid 500); 28 Sep 2012 08:41:28 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 98839 invoked by uid 500); 28 Sep 2012 08:41:24 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 98802 invoked by uid 99); 28 Sep 2012 08:41:23 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Sep 2012 08:41:23 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 28 Sep 2012 08:41:22 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 1689223889C5 for ; Fri, 28 Sep 2012 08:40:39 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1391362 - in /tomcat/sandbox/trunk-resources: java/org/apache/catalina/ java/org/apache/catalina/core/ java/org/apache/catalina/webresources/ test/org/apache/catalina/webresources/ Date: Fri, 28 Sep 2012 08:40:38 -0000 To: dev@tomcat.apache.org From: markt@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120928084039.1689223889C5@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: markt Date: Fri Sep 28 08:40:38 2012 New Revision: 1391362 URL: http://svn.apache.org/viewvc?rev=1391362&view=rev Log: Further work on the caching implementation - If a CachedResource fails validation, remove it from the cache and replace it rather than update it as this makes it much easier to track the current cache size. - Track the current cache size - Add configuration for the maximum cache size - Start implementing (not finished) the background expiration Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java tomcat/sandbox/trunk-resources/java/org/apache/catalina/core/StandardContext.java tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/WebResourceRoot.java Fri Sep 28 08:40:38 2012 @@ -255,6 +255,9 @@ public interface WebResourceRoot extends */ long getCacheTtl(); + void setCacheMaxSize(long cacheMaxSize); + long getCacheMaxSize(); + /** * This method will be invoked by the context on a periodic basis and allows * the implementation a method that executes periodic tasks, such as purging Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/core/StandardContext.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/core/StandardContext.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/core/StandardContext.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/core/StandardContext.java Fri Sep 28 08:40:38 2012 @@ -4773,13 +4773,13 @@ public class StandardContext extends Con resources.setAllowLinking(isAllowLinking()); - resources.setCacheTtl(getCacheTTL()); resources.setCachingAllowed(isCachingAllowed()); + resources.setCacheTtl(getCacheTTL()); + resources.setCacheMaxSize(getCacheMaxSize()); resources.start(); // TODO: Implement caching. - // getCacheMaxSize() // getCacheMaxObjectSize() if (effectiveMajorVersion >=3 && addWebinfClassesResources) { Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/Cache.java Fri Sep 28 08:40:38 2012 @@ -18,14 +18,23 @@ package org.apache.catalina.webresources import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; import org.apache.catalina.WebResource; public class Cache { + // Estimate (on high side to be safe) of average size excluding content + // based on profiler data. + private static final long CACHE_ENTRY_SIZE = 500; + + private static final long TARGET_FREE_PERCENT = 5; + private final StandardRoot root; + private final AtomicLong size = new AtomicLong(0); private long ttl = 5000; + private long maxSize = 10 * 1024 * 1024; private ConcurrentMap resourceCache = new ConcurrentHashMap<>(); @@ -35,25 +44,61 @@ public class Cache { } protected WebResource getResource(String path) { - // Multiple concurrent callers will end up with the same CachedResource - // instance - CachedResource newCacheEntry = new CachedResource(root, path, ttl); - CachedResource result = - resourceCache.putIfAbsent(path, newCacheEntry); + CachedResource cacheEntry = resourceCache.get(path); - if (result == null) { - result = newCacheEntry; + if (cacheEntry != null && !cacheEntry.validate()) { + removeCacheEntry(path); + cacheEntry = null; } - // TODO check cache size and do minimum necessary to make room - // TODO Cache size configuration - result.validate(); + if (cacheEntry == null) { + // Concurrent callers will end up with the same CachedResource + // instance + CachedResource newCacheEntry = new CachedResource(root, path, ttl); + cacheEntry = resourceCache.putIfAbsent(path, newCacheEntry); + + if (cacheEntry == null) { + // newCacheEntry was inserted into the cache - validate it + cacheEntry = newCacheEntry; + cacheEntry.validate(); + + // Assume that the cache entry will include the content. + // This isn't always the case but it makes tracking the + // current cache size easier. + long delta = CACHE_ENTRY_SIZE; + delta += cacheEntry.getContentLength(); + size.addAndGet(delta); + + if (size.get() > maxSize) { + // TODO make room + } + } else { + // Another thread added the entry to the cache + // Make sure it is validated + cacheEntry.validate(); + } + } - return result; + return cacheEntry; } protected void backgroundProcess() { - // TODO expiration + long targetSize = maxSize * (100 - TARGET_FREE_PERCENT) / 100; + + while (targetSize > size.get()) { + // TODO ID resources to remove + } + } + + private void removeCacheEntry(String path) { + // With concurrent calls for the same path, the entry is only removed + // once and the cache size is only updated once. + CachedResource cachedResource = resourceCache.remove(path); + if (cachedResource != null) { + long delta = + 0 - CACHE_ENTRY_SIZE - cachedResource.getContentLength(); + size.addAndGet(delta); + } } public long getTtl() { @@ -63,4 +108,12 @@ public class Cache { public void setTtl(long ttl) { this.ttl = ttl; } + + public long getMaxSize() { + return maxSize; + } + + public void setMaxSize(long maxSize) { + this.maxSize = maxSize; + } } Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/CachedResource.java Fri Sep 28 08:40:38 2012 @@ -52,43 +52,34 @@ public class CachedResource implements W this.ttl = ttl; } - protected void validate() { + protected boolean validate() { long now = System.currentTimeMillis(); if (webResource == null) { synchronized (this) { if (webResource == null) { - WebResource result = root.getResourceInternal(webAppPath); - webResource = result; + webResource = root.getResourceInternal(webAppPath); + getLastModified(); + getContentLength(); nextCheck = ttl + now; - return; + return true; } } } if (now < nextCheck) { - return; + return true; } - synchronized (this) { - if (now < nextCheck) { - return; - } - - if (webResource.getLastModified() + ttl >= nextCheck) { - WebResource result = root.getResourceInternal(webAppPath); - webResource = result; - - cachedContent = null; - cachedContentLength = null; - cachedExists = null; - cachedIsDirectory = null; - cachedIsFile = null; - cachedLastModified = null; - cachedLastModifiedHttp = null; - } - nextCheck = ttl + now; + // If modified date or length change - resource has changed / been + // removed etc. + if (webResource.getLastModified() != getLastModified() || + webResource.getContentLength() != getContentLength()) { + return false; } + + nextCheck = ttl + now; + return true; } Modified: tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java (original) +++ tomcat/sandbox/trunk-resources/java/org/apache/catalina/webresources/StandardRoot.java Fri Sep 28 08:40:38 2012 @@ -321,6 +321,16 @@ public class StandardRoot extends Lifecy } @Override + public long getCacheMaxSize() { + return cache.getMaxSize(); + } + + @Override + public void setCacheMaxSize(long cacheMaxSize) { + cache.setMaxSize(cacheMaxSize); + } + + @Override public Context getContext() { return context; } Modified: tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java URL: http://svn.apache.org/viewvc/tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java?rev=1391362&r1=1391361&r2=1391362&view=diff ============================================================================== --- tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java (original) +++ tomcat/sandbox/trunk-resources/test/org/apache/catalina/webresources/TesterWebResourceRoot.java Fri Sep 28 08:40:38 2012 @@ -167,6 +167,16 @@ public class TesterWebResourceRoot imple } @Override + public void setCacheMaxSize(long cacheMaxSize) { + // NO-OP + } + + @Override + public long getCacheMaxSize() { + return 0; + } + + @Override public void addPreResources(WebResourceSet webResourceSet) { // NO-OP } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org