(tomcat) branch main updated: Use LRU order for persistent session swaps (#1045)

[email protected]
Newsgroups gmane.comp.jakarta.tomcat.devel
Message-ID <178696396008.1868722.2045115463279651783@gitbox3-he-fi.apache.org>
This is an automated email from the ASF dual-hosted git repository.

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


The following commit(s) were added to refs/heads/main by this push:
     new 9a59ef2717 Use LRU order for persistent session swaps (#1045)
9a59ef2717 is described below

commit 9a59ef27179803bf0f03f9ce517c58f8bb7b1029
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 6d8e0727aa..f92b88fe94 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -253,6 +253,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. (sainadh777)
+      </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.