You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by sh...@brm.com on 2000/12/24 22:26:39 UTC

[PATCH] Tomcat session replicator - Pathces for phase I

Hi,


These patches will allow you to add serialize="true" to you context and
having your context saved to disk.

Index: src/share/org/apache/tomcat/core/Context.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/Context.java
,v
retrieving revision 1.129
diff -w -u -r1.129 Context.java
--- src/share/org/apache/tomcat/core/Context.java	2000/12/13 19:58:01
1.129
+++ src/share/org/apache/tomcat/core/Context.java	2000/12/24 21:20:34
@@ -81,6 +81,9 @@
  * You need to set at least "path" and "base" before adding a
  * context to a server. You can also set any other properties.
  *
+ * Setting context's serialize attribute to true will cause it dump its
+ * session information to file on request end, startup and shutdown.
+ *
  * At addContext() stage log and paths will be "fixed" based on
  * context manager settings.
  *
@@ -94,6 +97,7 @@
  * @author Harish Prabandham
  * @author costin@dnt.ro
  * @author Gal Shachor shachor@il.ibm.com
+ * @author Shai Fultheim [shai@brm.com]
  */
 public final class Context implements LogAware {
     // -------------------- Constants --------------------
@@ -172,6 +176,9 @@
     // enable reloading
     private boolean reloadable=true; 
 
+	// enable serialization
+	private boolean serialize = false;
+
     // XXX Use a better repository
     private Hashtable attributes = new Hashtable();
 
@@ -558,6 +565,16 @@
 	return reloadable;
     }
 
+	public void setSerialize( boolean b ) {
+		   serialize=b;
+	}
+
+	/** Should we serialize sessions ?
+	 */
+	public boolean getSerialize() {
+		   return serialize;
+	}
+
     // -------------------- API level --------------------
     
     /** The servlet API variant that will be used for requests in this
@@ -1075,4 +1092,15 @@
         defaultContainer.addInterceptor(ri);
     }
 
+	public final String getFileName() {
+		return System.getProperty("tomcat.home") + "/bin/Sessions" +
cleanupFileName(getPath()) + ".ses";
+	}
+
+	private String cleanupFileName(String fn) {
+		String f = fn;
+		f = f.replace('/','_');
+		f = f.replace('\\','_');
+
+		return f;
+	}
 }
Index: src/share/org/apache/tomcat/core/ContextManager.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManag
er.java,v
retrieving revision 1.157
diff -w -u -r1.157 ContextManager.java
--- src/share/org/apache/tomcat/core/ContextManager.java	2000/12/08
23:18:43	1.157
+++ src/share/org/apache/tomcat/core/ContextManager.java	2000/12/24
21:20:37
@@ -62,6 +62,7 @@
 
 import org.apache.tomcat.util.*;
 import org.apache.tomcat.util.log.*;
+import org.apache.tomcat.session.ServerSession;
 import java.io.*;
 import java.net.*;
 import java.util.*;
@@ -180,6 +181,7 @@
   @author Harish Prabandham
   @author costin@eng.sun.com
   @author Hans Bergsten [hans@gefionsoftware.com]
+  @author Shai Fultheim [shai@brm.com]
  */
 public final class ContextManager implements LogAware{
     /** Official name and version
@@ -713,6 +715,23 @@
 	    for( int i=0; i< reqI.length; i++ ) {
 		reqI[i].postRequest( req, res );
 	    }
+
+		if ((req.getSession(false) != null) &&
req.getContext().getSerialize()) {
+			Context ctx = req.getContext();
+
+			ServerSession ses = req.getSession(false);
+
+			if (debug > 0 ) {
+				log("Serializing session " + ses.getId() +
+					", lasted  " +
(ses.getTimeStamp().getLastAccessedTime() -
+
ses.getTimeStamp().getCreationTime())/1000 +
+					" Secs.");
+			}
+
+			File f = new File(ctx.getFileName());
+			ses.getSessionManager().serializeSessions(f);
+		}
+
 	    req.recycle();
 	    res.recycle();
 	}
Index: src/share/org/apache/tomcat/modules/session/SimpleSessionStore.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/modules/session/S
impleSessionStore.java,v
retrieving revision 1.4
diff -w -u -r1.4 SimpleSessionStore.java
--- src/share/org/apache/tomcat/modules/session/SimpleSessionStore.java
2000/11/30 06:17:12	1.4
+++ src/share/org/apache/tomcat/modules/session/SimpleSessionStore.java
2000/12/24 21:20:39
@@ -249,6 +249,16 @@
 	}
 	sm.setMaxActiveSessions( maxActiveSessions );
 
+		if (ctx.getSerialize()) {
+			String fileName = ctx.getFileName();
+
+			File f = new File(fileName);
+			if (f.exists()) {
+				if( ctx.getDebug() > 0 )
ctx.log("deSerializing sessions from " + fileName);
+				sm.deSerializeSessions(f);
+			}
+		}
+
 	Expirer expirer=new Expirer();
 	expirer.setCheckInterval( checkInterval );
 	expirer.setExpireCallback( new Expirer.ExpireCallback() {
@@ -272,6 +282,14 @@
 	if( debug > 0 ) ctx.log("Removing sessions from " + ctx );
 	ServerSessionManager sm=getManager(ctx);
 	sm.getExpirer().stop();
+
+		if (ctx.getSerialize()) {
+			String fileName = ctx.getFileName();
+
+			File f = new File(fileName);
+			if( debug > 0 ) ctx.log("Serializing sessions from "
+ fileName);
+			sm.serializeSessions(f);
+		}
 	sm.removeAllSessions();
     }
 
@@ -279,7 +297,4 @@
     private ServerSessionManager getManager( Context ctx ) {
 	return
(ServerSessionManager)ctx.getContainer().getNote(manager_note);
     }
-
-
-
 }
Index: src/share/org/apache/tomcat/session/ServerSession.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSes
sion.java,v
retrieving revision 1.8
diff -w -u -r1.8 ServerSession.java
--- src/share/org/apache/tomcat/session/ServerSession.java	2000/11/22
00:09:59	1.8
+++ src/share/org/apache/tomcat/session/ServerSession.java	2000/12/24
21:20:40
@@ -82,6 +82,7 @@
  * @author Craig R. McClanahan
  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
  * @author Costin Manolache
+ * @author Shai Fultheim [shai@brm.com]
  */
 public final class ServerSession  implements  Serializable {
     private static StringManager sm =
@@ -161,5 +162,12 @@
 	ts.recycle();
 	id.recycle();
     }
+
+	private void writeObject(ObjectOutputStream s) throws IOException {
+		ServerSessionManager orig  = ssm;
+		ssm = null;
+		s.defaultWriteObject();
+		ssm = orig;
+	}
 }
Index: src/share/org/apache/tomcat/session/ServerSessionManager.java
===================================================================
RCS file:
/home/cvspublic/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSes
sionManager.java,v
retrieving revision 1.14
diff -w -u -r1.14 ServerSessionManager.java
--- src/share/org/apache/tomcat/session/ServerSessionManager.java
2000/12/07 19:52:46	1.14
+++ src/share/org/apache/tomcat/session/ServerSessionManager.java
2000/12/24 21:20:41
@@ -61,6 +61,7 @@
 package org.apache.tomcat.session;
 
 import java.io.IOException;
+import java.io.*;
 import java.util.*;
 import org.apache.tomcat.util.*;
 import org.apache.tomcat.util.collections.SimplePool;
@@ -70,8 +71,8 @@
 import org.apache.tomcat.util.log.*;
 
 /**
+ * @author Shai Fultheim [shai@brm.com]
  *
- * 
  */
 public final class ServerSessionManager  
 {
@@ -226,4 +227,58 @@
 	}
     }
 
+
+	public void serializeSessions(File f) {
+		if (sessions.size() == 0)
+		   return;
+
+		FileOutputStream fStream = null;
+		ObjectOutputStream oStream = null;
+
+		try {
+			fStream = new FileOutputStream(f);
+			oStream = new ObjectOutputStream(fStream);
+			// Serialize to file all active session
+			Enumeration ids = sessions.keys();
+			ServerSession session = null;
+			while (ids.hasMoreElements()) {
+				session =
findSession(ids.nextElement().toString());
+				if (!session.getTimeStamp().isValid())
+				   continue;
+				oStream.writeObject(session);
+			}
+			oStream.flush();
+			fStream.close();
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+	}
+
+	public void deSerializeSessions(File f)
+	{
+		FileInputStream fStream = null;
+		try {
+			fStream = new FileInputStream(f);
+			ObjectInputStream oStream = new
ObjectInputStream(fStream);
+			ServerSession session = null;
+			do {
+				session =
(ServerSession)oStream.readObject();
+				if (session != null) {
+					session.ssm = this;
+					sessions.put(session.getId(),
session);
+				}
+			} while (session != null);
+		} catch (java.io.FileNotFoundException n) {
+			;
+		} catch (java.io.EOFException eof) {
+			try {
+				fStream.close();
+			} catch (Exception e) {
+				System.out.println(e);
+			}
+		} catch (Exception e) {
+			System.out.println(e);
+		}
+		f.delete();
+	}
 }



________________________
Shai Fultheim
Chief Technology Officer
BRM Seed
 
E-Mail: shai@brm.com
Mobile: 972-53-866-459
Office: 972-2-5891-459


Re: [PATCH] Tomcat session replicator - Pathces for phase I

Posted by Jon Stevens <jo...@latchkey.com>.
on 12/24/2000 1:26 PM, "shai@brm.com" <sh...@brm.com> wrote:

> try {
> +   fStream = new FileOutputStream(f);
> +   oStream = new ObjectOutputStream(fStream);
> +   // Serialize to file all active session
> +   Enumeration ids = sessions.keys();
> +   ServerSession session = null;
> +   while (ids.hasMoreElements()) {
> +    session =
> findSession(ids.nextElement().toString());
> +    if (!session.getTimeStamp().isValid())
> +       continue;
> +    oStream.writeObject(session);
> +   }
> +   oStream.flush();
> +   fStream.close();
> +  } catch (Exception e) {
> +   System.out.println(e);
> +  }
> + }

I keep looking at this code and realizing how bad it is. :-(

You also should have the streams closed in a try/finally statement instead
of just attempting to close them at the end.

thanks,

-jon


Re: [PATCH] Tomcat session replicator - Pathces for phase I

Posted by Jon Stevens <jo...@latchkey.com>.
on 12/24/2000 1:26 PM, "shai@brm.com" <sh...@brm.com> wrote:

> +  try {
> +   fStream = new FileOutputStream(f);
> +   oStream = new ObjectOutputStream(fStream);
> +   // Serialize to file all active session
> +   Enumeration ids = sessions.keys();
> +   ServerSession session = null;
> +   while (ids.hasMoreElements()) {
> +    session =
> findSession(ids.nextElement().toString());
> +    if (!session.getTimeStamp().isValid())
> +       continue;
> +    oStream.writeObject(session);
> +   }
> +   oStream.flush();
> +   fStream.close();
> +  } catch (Exception e) {
> +   System.out.println(e);
> +  }
> + }

-1

You need to do checks in here to make sure that the object that you are
trying to serialize actually implements Serializable otherwise you are going
to be screwed because as soon as you hit the object that isn't Serializable,
then you are going to throw the exception and the rest of your sessions are
not going to be serialized.

This is yet another reason why the Servlet API spec should only allow people
to place Serializable objects into the Session.

love,

-jon

-- 
Honk if you love peace and quiet.



Re: [PATCH] Tomcat session replicator - Pathces for phase I

Posted by cm...@yahoo.com.
Hi Shai,

Thanks for your patch, it's a very good start and I think it'll be useful
for many users. 

I think it needs some more work - I'm not talking about the main
functionality you are implementing, which I'm sure will be tested and
improved and will have a nice evolution.

I'm talking  as a person who spent a lot of time refactoring tomcat3.x,
and ( I hope ) I learned something from it.

The most important thing I learned in the last year is: "don't add
anything to the core unless you are _absolutely_ sure it can't be
done in a module". The reason tomcat3.0 was so bad is that people kept
adding new features _in_the_core_ and everything ended up in a total mess.

For example:

- you can implement the same thing as a new "SerializableSession" module

- the new module _doesn't_ have to be part of 3.3 - in fact it's much
better to have it as an optional module until it's well tested.

- the property you add to Context ( "serialize" ) could  be added 
to the new module ( togheter with other options, describing how and when
should serialization happen )

- the user could add the module to his system and add it to the Context
he wants 

- what you do in ContextManager is a perfect example of use of postRequest
hook - it'll be part of the SSI.postRequest(). The benefit is that it'll
happen _only_ for contexts that need the feature ( instead of adding it to
all requetsts - remember, the call to getSession() is expensive, and
you'll do it for servlets that never cared for sessions - thus adding 
overhead for all requests)


- your module will be the first session-manager plugin for 3.3. This is
where your contribution will be the most important - in figuring out what
is the best way to plug a new session manager.
My current view is that we need to extend ServerSession, SessionManager
and use a different Interceptor  - it is possible to do that, but it's
still a bit too complex for my taste.


Let me say again - what you do in this patch is what I ( and probably most
other developers ) would have done to resolve a particular problem. It's
what pre-3.0 developers did.

If you change it to work as a module you'll have probably a bit more work
( let me know if I can help - after a year of refactoring tomcat I think I
can deal with such a small patch in a very short time :-). 

The benefits:

- no change in the core - keep it simple

- it can evolve independently of tomcat release cycles - as you know
after 3.3 is out ( inside or outside apache ) we want to avoid any further
changes. You module may evolve quickly - there are many ideas to explore.

- you don't need to argue with people like Jon about it :-) - it doesn't
have to be part of tomcat3.3, it's an add-on module. In general, there is
no need to argue with anyone - if the modules is good for you, I'm sure
other will like it, and who doesn't like it is free not to use it.

- there is more than one way to do it - other ideas could be developed,
maybe we would want to serialize the session periodicaly ( not
per/request), or use a MM-like system, etc - by not adding the changes to
ContextManager but in the postRequest hook we could have any combination
of those.

What do you think ?

Costin

P.S. 
- finally a technical issue - I will not answer to anything else.

- I'm reading my own mails, and I'm amazed about how much I wrote in 
the last weeks (about almost nothing :-). Since it doesn't happen to me
too often ( to write a lot of "english" ) I'll try to refocus it into
improving the "internal" documentation of tomcat 3.3 :-)


Re: [PATCH] Tomcat session replicator - Pathces for phase I

Posted by Jon Stevens <jo...@latchkey.com>.
on 12/24/2000 1:26 PM, "shai@brm.com" <sh...@brm.com> wrote:

> +   while (ids.hasMoreElements()) {
> +    session =
> findSession(ids.nextElement().toString());
> +    if (!session.getTimeStamp().isValid())
> +       continue;
> +    oStream.writeObject(session);
> +   }
> +   oStream.flush();
> +   fStream.close();
> +  } catch (Exception e) {
> +   System.out.println(e);
> +  }
> + }

One more thing about this that you need to consider...if the object
implements HttpSessionBindingListerWayToLongInterfaceName, then you should
consider calling its valueUnbound() methods before doing the serialization
otherwise you are not giving the object you are serializing a chance to do
what it needs to do.

Also, I already wrote all of this code for JServ and Tomcat 3.x and you
aren't even re-using it. Sigh.

love,

-jon