This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit f2a18140e53a933f889efa71ae34d08f568c028c
Author: opencode <[email protected]>
AuthorDate: Mon Oct 19 12:04:57 2026 +0200

    Record JSP usage time on every request, fixing premature idle unload
    
    JspServletWrapper.service() only advanced the wrapper's lastUsageTime
    when it was older than the timestamp of the previous background
    checkUnload() run, a gate introduced to limit jspQueue re-ordering to
    a single move per background cycle. When the jspIdleTimeout feature
    was added it reused the same gate for lastUsageTime, so the timestamp
    of an actively requested JSP advanced at most once per background
    processor cycle (default 10s). With jspIdleTimeout shorter than that
    cycle, JspRuntimeContext.checkUnload() saw continuously used JSPs as
    idle and unloaded them repeatedly, forcing needless recompilation and
    class loader churn; the LRU queue ordering was likewise stale by up to
    one cycle.
    
    Keep the once-per-cycle throttle for the makeYoungest() queue
    re-ordering, which was its original purpose (commit ee86d455a5), but
    record lastUsageTime unconditionally inside the already held wrapper
    lock, so the idle timeout check always sees the true last usage.
    
    Found by code review.
---
 java/org/apache/jasper/servlet/JspServletWrapper.java | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/jasper/servlet/JspServletWrapper.java 
b/java/org/apache/jasper/servlet/JspServletWrapper.java
index ff7dc8ee2e..7fe86af467 100644
--- a/java/org/apache/jasper/servlet/JspServletWrapper.java
+++ b/java/org/apache/jasper/servlet/JspServletWrapper.java
@@ -486,14 +486,15 @@ public class JspServletWrapper {
                         if (unloadHandle == null) {
                             unloadHandle = ctxt.getRuntimeContext().push(this);
                         } else if (lastUsageTime < 
ctxt.getRuntimeContext().getLastJspQueueUpdate()) {
+                            // Limit queue re-ordering to a single move per
+                            // background checkUnload() cycle.
                             
ctxt.getRuntimeContext().makeYoungest(unloadHandle);
-                            lastUsageTime = System.currentTimeMillis();
-                        }
-                    } else {
-                        if (lastUsageTime < 
ctxt.getRuntimeContext().getLastJspQueueUpdate()) {
-                            lastUsageTime = System.currentTimeMillis();
                         }
                     }
+                    // Always record the usage time, so an actively used JSP is
+                    // never seen as idle by checkUnload(), independent of how
+                    // often the queue order above was updated.
+                    lastUsageTime = System.currentTimeMillis();
                 }
             }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to