(tomcat) 01/02: Use LRU order for persistent session swaps (#1045)

[email protected]
Newsgroups gmane.comp.jakarta.tomcat.devel
Message-ID <[email protected]>
This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 9968ee3e34ba31a00dd7faf2974a60b1ba6c6634
Author: sainadh777 <[email protected]>
AuthorDate: Mon Aug 17 03:52:34 2026 -0700

    Use LRU order for persistent session swaps (#1045)
---
 .../catalina/session/PersistentManagerBase.java    |  3 +-
 .../catalina/session/TestPersistentManager.java    | 54 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  5 ++
 3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/catalina/session/PersistentManagerBase.java b/java/org/apache/catalina/session/PersistentManagerBase.java
index 019925cc8a..13d6a1fa7d 100644
--- a/java/org/apache/catalina/session/PersistentManagerBase.java
+++ b/java/org/apache/catalina/session/PersistentManagerBase.java
@@ -18,6 +18,7 @@ package org.apache.catalina.session;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -797,7 +798,6 @@ public abstract class PersistentManagerBase extends ManagerBase implements Store
 
         Session[] sessions = findSessions();
 
-        // FIXME: Smarter algorithm (LRU)
         int limit = (int) (getMaxActiveSessions() * 0.9);
 
         if (limit >= sessions.length) {
@@ -809,6 +809,7 @@ public abstract class PersistentManagerBase extends ManagerBase implements Store
         }
 
         int toswap = sessions.length - limit;
+        Arrays.sort(sessions, Comparator.comparingLong(Session::getLastAccessedTimeInternal));
 
         for (int i = 0; i < sessions.length && toswap > 0; i++) {
             StandardSession session = (StandardSession) sessions[i];
diff --git a/test/org/apache/catalina/session/TestPersistentManager.java b/test/org/apache/catalina/session/TestPersistentManager.java
index be95c26687..2f6518c370 100644
--- a/test/org/apache/catalina/session/TestPersistentManager.java
+++ b/test/org/apache/catalina/session/TestPersistentManager.java
@@ -71,6 +71,38 @@ public class TestPersistentManager {
         Assert.assertEquals(3, manager.getActiveSessionsFull());
     }
 
+    @Test
+    public void testMaxActiveSwapUsesLeastRecentlyUsed() throws Exception {
+        OrderedPersistentManager manager = new OrderedPersistentManager();
+        TesterStore store = new TesterStore();
+        manager.setStore(store);
+
+        Host host = new TesterHost();
+        Context context = new TesterContext();
+        context.setParent(host);
+
+        manager.setContext(context);
+        manager.setMaxActiveSessions(3);
+        manager.setMinIdleSwap(0);
+
+        manager.start();
+
+        StandardSession oldest = (StandardSession) manager.createSession("oldest");
+        StandardSession middle = (StandardSession) manager.createSession("middle");
+        StandardSession newest = (StandardSession) manager.createSession("newest");
+
+        long now = System.currentTimeMillis();
+        oldest.lastAccessedTime = now - 30000;
+        middle.lastAccessedTime = now - 20000;
+        newest.lastAccessedTime = now - 10000;
+
+        manager.setOrderedSessions(newest, middle, oldest);
+        manager.processMaxActiveSwaps();
+
+        Assert.assertEquals(1, store.getSavedIds().size());
+        Assert.assertEquals("oldest", store.getSavedIds().get(0));
+    }
+
     @Test
     public void testBug62175() throws Exception {
         PersistentManager manager = new PersistentManager();
@@ -138,6 +170,28 @@ public class TestPersistentManager {
         }
     }
 
+    private static class OrderedPersistentManager extends PersistentManagerBase {
+
+        private Session[] orderedSessions;
+
+        void setOrderedSessions(Session... orderedSessions) {
+            this.orderedSessions = orderedSessions;
+        }
+
+        @Override
+        public Session[] findSessions() {
+            if (orderedSessions == null) {
+                return super.findSessions();
+            }
+            return orderedSessions;
+        }
+
+        @Override
+        public String getName() {
+            return "OrderedPersistentManager";
+        }
+    }
+
     private StandardSession timedOutSession(PersistentManager manager, AtomicInteger counter) {
         StandardSession timedOutSession = new StandardSession(manager) {
             private static final long serialVersionUID = -5910605558747844210L;
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 07a6401f3a..0bc65c5c8e 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -122,6 +122,11 @@
         Ensure that capture groups from a <code>RewriteCond</code> always
         reflect the result of the current request. (markt)
       </fix>
+      <fix>
+        When a <code>PersistentManager</code> needs to reduce the number of
+        active sessions, swap out the least recently used eligible sessions
+        first. Pull request <pr>1045</pr> provided by sainadh777. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.