Skip to content

Commit

Permalink
build checksum only from attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
madness-inc committed Dec 17, 2021
1 parent 3e30293 commit 9829f68
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 25 deletions.
5 changes: 2 additions & 3 deletions src/main/java/org/appng/tomcat/session/SessionData.java
Expand Up @@ -16,7 +16,6 @@
package org.appng.tomcat.session;

import java.io.Serializable;
import java.util.Arrays;

/**
* Used to persist the binary representation of {@link org.apache.catalina.Session}.
Expand All @@ -28,11 +27,11 @@ public class SessionData implements Serializable {
private final byte[] data;
private final int checksum;

public SessionData(String id, String site, byte[] data) {
public SessionData(String id, String site, byte[] data, int checksum) {
this.id = id;
this.site = site;
this.data = data;
this.checksum = Arrays.hashCode(data);
this.checksum = checksum;
}

public String getSite() {
Expand Down
Expand Up @@ -15,12 +15,17 @@
*/
package org.appng.tomcat.session.hazelcast;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Principal;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.apache.catalina.Manager;
import org.apache.catalina.Session;
Expand All @@ -34,7 +39,7 @@ public class HazelcastSession extends org.apache.catalina.session.StandardSessio

private static String DIRTY_FLAG = "__changed__";
private static final long serialVersionUID = -5219705900405324572L;
protected transient boolean dirty = false;
protected volatile transient boolean dirty = false;

public HazelcastSession(Manager manager) {
super(manager);
Expand Down Expand Up @@ -81,6 +86,25 @@ public SessionData serialize() throws IOException {
return serialize(null);
}

public int checksum() throws IOException {
Map<String, Object> attributes = new HashMap<String, Object>();
for (Enumeration<String> enumerator = getAttributeNames(); enumerator.hasMoreElements();) {
String key = enumerator.nextElement();
if (!DIRTY_FLAG.equals(key)) {
attributes.put(key, getAttribute(key));
}
}

try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos));) {
oos.writeUnshared(attributes);
oos.flush();
bos.flush();
int checksum = Arrays.hashCode(bos.toByteArray());
return checksum;
}
}

public SessionData serialize(String alternativeSiteName) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
Expand All @@ -89,7 +113,7 @@ public SessionData serialize(String alternativeSiteName) throws IOException {
oos.flush();
bos.flush();
String siteName = null == alternativeSiteName ? Utils.getSiteName(this) : alternativeSiteName;
return new SessionData(getId(), siteName, bos.toByteArray());
return new SessionData(getId(), siteName, bos.toByteArray(), checksum());
}
}

Expand All @@ -100,8 +124,8 @@ public static HazelcastSession create(Manager manager, SessionData sessionData)
HazelcastSession session = (HazelcastSession) manager.createEmptySession();
session.readObjectData(ois);
session.access();
session.endAccess();
session.setClean();
manager.add(session);
return session;
}
}
Expand Down
Expand Up @@ -17,6 +17,7 @@

import java.io.IOException;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.catalina.LifecycleException;
Expand All @@ -35,6 +36,7 @@

public class HazelcastManager extends ManagerBase {

private static final double NANOS_TO_MILLIS = 1000000d;
private final Log log = Utils.getLog(HazelcastManager.class);
private String configFile = "WEB-INF/classes/hazelcast.xml";
private String mapName = "tomcat.sessions";
Expand Down Expand Up @@ -86,17 +88,21 @@ boolean commit(Session session) throws IOException {

boolean commit(Session session, String alternativeSiteName) throws IOException {
HazelcastSession hzSession = HazelcastSession.class.cast(session);
long start = System.currentTimeMillis();
SessionData currentSessionData = null;
if (hzSession.isDirty() || getPersistentSessions().get(session.getId())
.checksum() != (currentSessionData = hzSession.serialize(alternativeSiteName)).checksum()) {
SessionData sessionData = null == currentSessionData ? hzSession.serialize() : currentSessionData;
long start = System.nanoTime();
int oldChecksum = -1;
boolean sessionDirty = false;
if ((sessionDirty = hzSession.isDirty())
|| (oldChecksum = getPersistentSessions().get(session.getId()).checksum()) != hzSession.checksum()) {
SessionData sessionData = hzSession.serialize(alternativeSiteName);
getPersistentSessions().set(session.getId(), sessionData);
if (log.isDebugEnabled()) {
log.debug(String.format("Saved %s in %dms", sessionData, System.currentTimeMillis() - start));
String reason = sessionDirty ? "dirty-flag was set" : String.format("checksum <> %s", oldChecksum);
log.debug(String.format(Locale.ENGLISH, "Saved %s (%s) in %.2fms", sessionData, reason,
((System.nanoTime() - start)) / NANOS_TO_MILLIS));
}
return true;

} else if (log.isTraceEnabled()) {
log.trace(String.format("No changes in %s", session.getId()));
}
return false;
}
Expand All @@ -105,11 +111,9 @@ boolean commit(Session session, String alternativeSiteName) throws IOException {
public HazelcastSession findSession(String id) throws IOException {
HazelcastSession session = (HazelcastSession) super.findSession(id);
if (null == session) {

long start = System.currentTimeMillis();

// the calls are performed in a pessimistic lock block to prevent concurrency problems whilst finding
// sessions
long start = System.nanoTime();
// the calls are performed in a pessimistic lock block to prevent
// concurrency problems whilst finding sessions
getPersistentSessions().lock(id);
try {
SessionData sessionData = getPersistentSessions().get(id);
Expand All @@ -121,10 +125,9 @@ public HazelcastSession findSession(String id) throws IOException {
try {
session = HazelcastSession.create(this, sessionData);
if (log.isDebugEnabled()) {
log.debug(String.format("Loaded %s in %dms", sessionData,
System.currentTimeMillis() - start));
log.debug(String.format(Locale.ENGLISH, "Loaded %s in %.2fms", sessionData,
((System.nanoTime() - start)) / NANOS_TO_MILLIS));
}
add(session);
} catch (ClassNotFoundException e) {
log.error("Error loading session" + id, e);
}
Expand All @@ -134,7 +137,6 @@ public HazelcastSession findSession(String id) throws IOException {
}
} else {
session.access();
session.endAccess();
}
return session;
}
Expand Down
Expand Up @@ -56,26 +56,38 @@ public void test() throws Exception {
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());

int checkSum1 = session.checksum();

Assert.assertFalse(session.isDirty());
session.setAttribute("foo", "test");
HashMap<String, String> map = new HashMap<String, String>();
session.setAttribute("amap", map);
session.setAttribute("metaData", new MetaData());

int checkSum2 = session.checksum();
Assert.assertNotEquals(checkSum1, checkSum2);

Assert.assertTrue(session.isDirty());
Assert.assertTrue(manager.commit(session));
Assert.assertFalse(session.isDirty());
Assert.assertFalse(manager.commit(session));

SessionData original = session.serialize();
int checksum = original.checksum();
int checksum3 = original.checksum();

Assert.assertEquals(checkSum2, checksum3);

map.put("foo", "test");
SessionData modified = session.serialize();
int newChecksum = modified.checksum();
Assert.assertNotEquals(checksum, newChecksum);
int checksum4 = modified.checksum();
Assert.assertNotEquals(checksum3, checksum4);
Assert.assertTrue(manager.commit(session));

long accessedBefore = session.getThisAccessedTimeInternal();
HazelcastSession loaded = manager.findSession(session.getId());
Assert.assertEquals(session, loaded);
long accessedAfter = session.getThisAccessedTimeInternal();
Assert.assertNotEquals(accessedBefore, accessedAfter);

Assert.assertEquals(1, manager.getActiveSessions());
manager.removeLocal(session);
Expand Down Expand Up @@ -152,6 +164,7 @@ public void sessionCreated(HttpSessionEvent se) {

@BeforeClass
public static void setup() throws LifecycleException {

context = new StandardContext();

manager = new HazelcastManager();
Expand Down

0 comments on commit 9829f68

Please sign in to comment.