On 01/10/2026 07:41, [email protected] wrote:
This is an automated email from the ASF dual-hosted git repository.

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

commit dd3554c534b46201746a742145a8f3933a8a7bc8
Author: opencode <[email protected]>
AuthorDate: Wed Sep 30 23:07:29 2026 +0200

     Compare type and action as well as name when de-duplicating DeltaRequest 
actions so that distinct changes sharing a name, such as an attribute and a 
note, are all replicated, and recycle the evicted action back to the pool

I don't think you want to include action when de-duplicating. Now a set then remove sequence sends both actions rather than just the remove.

Mark


---
  .../apache/catalina/ha/session/DeltaRequest.java   | 25 ++++++++++++++++------
  .../catalina/ha/session/TestDeltaRequest.java      | 25 ++++++++++++++++++++++
  2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/ha/session/DeltaRequest.java 
b/java/org/apache/catalina/ha/session/DeltaRequest.java
index 5a04057888..80f3491339 100644
--- a/java/org/apache/catalina/ha/session/DeltaRequest.java
+++ b/java/org/apache/catalina/ha/session/DeltaRequest.java
@@ -23,6 +23,7 @@ import java.io.ObjectOutputStream;
  import java.security.Principal;
  import java.util.ArrayDeque;
  import java.util.Deque;
+import java.util.Iterator;
import org.apache.catalina.SessionListener;
  import org.apache.catalina.realm.GenericPrincipal;
@@ -279,10 +280,16 @@ public class DeltaRequest implements Externalizable {
          // if we have already done something to this attribute, make sure
          // we don't send multiple actions across the wire
          if (!recordAllActions) {
-            try {
-                actions.remove(info);
-            } catch (java.util.NoSuchElementException x) {
-                // do nothing, we wanted to remove it anyway
+            Iterator<AttributeInfo> iterator = actions.iterator();
+            while (iterator.hasNext()) {
+                AttributeInfo existing = iterator.next();
+                if (existing.equals(info)) {
+                    iterator.remove();
+                    // Return the evicted action to the pool
+                    existing.recycle();
+                    actionPool.addLast(existing);
+                    break;
+                }
              }
          }
          // add the action
@@ -522,7 +529,9 @@ public class DeltaRequest implements Externalizable {
@Override
          public int hashCode() {
-            return name.hashCode();
+            // Must be consistent with equals() which compares name, type and
+            // action
+            return (name.hashCode() * 31 + type) * 31 + action;
          }
public String getName() {
@@ -541,7 +550,11 @@ public class DeltaRequest implements Externalizable {
              if (!(o instanceof AttributeInfo other)) {
                  return false;
              }
-            return other.getName().equals(this.getName());
+            // Attributes and notes are different stores and setting and
+            // removing are different changes, so a name match alone is not
+            // enough to consider two actions as the same change
+            return other.getType() == this.getType() && other.getAction() == 
this.getAction() &&
+                    other.getName().equals(this.getName());
          }
@Override
diff --git a/test/org/apache/catalina/ha/session/TestDeltaRequest.java 
b/test/org/apache/catalina/ha/session/TestDeltaRequest.java
index 17bf8672f4..b2e0db59ff 100644
--- a/test/org/apache/catalina/ha/session/TestDeltaRequest.java
+++ b/test/org/apache/catalina/ha/session/TestDeltaRequest.java
@@ -70,4 +70,29 @@ public class TestDeltaRequest {
          Assert.assertEquals("One", copySession.getAttribute("A"));
          Assert.assertEquals("Two", copySession.getAttribute("B"));
      }
+
+    /*
+     * Attributes and notes are separate stores. Setting an attribute and 
setting a note with the same name are two
+     * distinct changes and both must be replicated.
+     */
+    @Test
+    public void testAttributeAndNoteWithSameNameBothRecorded() {
+        DeltaRequest request = new DeltaRequest();
+        request.setSessionId("1234");
+        request.setAttribute("name", "value");
+        request.setNote("name", Integer.valueOf(1));
+        Assert.assertEquals(2, request.getSize());
+    }
+
+    /*
+     * Setting the same attribute twice should be recorded as a single action.
+     */
+    @Test
+    public void testRepeatedSetAttributeRecordedOnce() {
+        DeltaRequest request = new DeltaRequest();
+        request.setSessionId("1234");
+        request.setAttribute("name", "value1");
+        request.setAttribute("name", "value2");
+        Assert.assertEquals(1, request.getSize());
+    }
  }


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



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

Reply via email to