August 3, 2006

Improving GWT RPC Serialization Performance by a Factor of 10

So aparently serialization was taking 100% of my application
cpu time. I’ve made some changes to the serialization and my apps cpu usage has gone from 100% with about 7 tables running, (approximately 60-80 clients constantaly serializing)
down to 10%. So with the same load on the server the cpu has 90% free
cycles now!

This is from making a few simple changes to
ServerSerializableTypeOracleImpl. Here’s what I did:

1)  Add a new static map to the class…

private static final Map CUSTOM_FIELD_SERIALIZERS = new HashMap();

2)  Add static initialization to the class…

static{
try{
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.boolean_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.boolean_Array_CustomFieldSer­ializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Boolean”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Boolean_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.byte_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.byte_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Byte”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Byte_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.char_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.char_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Character”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Character_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.double_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.double_Array_CustomFieldSeri­alizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Double”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Double_CustomFieldSerializer­”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.float_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.float_Array_CustomFieldSeria­lizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Float”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Float_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.int_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.int_Array_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Integer”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Integer_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.long_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.long_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Long”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Long_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Object_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Object_Array_CustomFieldSeri­alizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.short_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.short_Array_CustomFieldSeria­lizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Short”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Short_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.String”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.String_CustomFieldSerializer­”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.ArrayList”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.ArrayList_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.Date”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.Date_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.HashMap”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.HashMap_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.HashSet”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.HashSet_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.Vector”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.Vector_CustomFieldSerializer­”
) );
        } catch (ClassNotFoundException e) {
      // purposely ignored
    }

}

 

3) Change hasCustomFieldSerializer to use this map….

 public Class hasCustomFieldSerializer(Class instanceType) {
    String qualifiedTypeName;
    if (instanceType.isArray()) {
      Class componentType = instanceType.getComponentType();
      if (componentType.isPrimitive()) {
        qualifiedTypeName = “java.lang.” + componentType.getName();
      } else {
        qualifiedTypeName = Object.class.getName();
      }
      qualifiedTypeName += “_Array”;
    } else {
      qualifiedTypeName = instanceType.getName();
    }
    return (Class)CUSTOM_FIELD_SERIALIZERS.get(qualifiedTypeName);

}

Thats it! Although this limits the custom field serializaers
extensibility it works very well for me since i don’t have any custom
serializers.

Filed under: google, java, gwt, google web toolkit, tomcat, gpokr
June 22, 2006

Running a GWT Servlet on a $6.99 Godaddy Account

I had some trouble yesterday getting this done. Here's what happened:

  1. I installed the jar files, both my jar file and gwt-user in /WEB-INF/lib through ftp. However tomcat loads these jar files when the server is restarted daily at 1am. This is a bit too long to wait for updates. The server does load class files immediatly. So I extracted both jars to /WEB-INF/classes.
  2. There was no need to play with a web.xml file. You can access your servlet at http://www.domainname.com/servlet/servletname, (replace domainname and servletname, not servlet).
  3. Running an HTTP GET on the servlet worked. So I ran GWT generated javascript to access the server. The RPC call failed. Debugging the javascript showed that it was a 500 Internal server error: Check the server logs for details.
  4. Checking the server logs revealed nothing. I Called godaddy a couple times, (thank god for free long distance on skype). They didn't know why the error didn't show up in the logs and the guy I spoke with the second time didn't know what a servlet was.
  5. I dug into the GWT source. The RemoteServiceServlet catchs all exceptions in the doPost method and passes them to the respondWithFailure method which adds the exception message to the tomcat log and returns the generic 500 internal error. I modified the source to return the exception and the stack.
  6. The exception was a java security restriction on java.lang.reflect and happened in ServerSerializationStream.serializeClass. In this method objects are serialized and each field is set to be accessible, that is if they are private fields they become accessible for serialization. This is what you can't do on godaddy's tomcat. The code is written such that every field's accessibility is changed whether its private or not.
  7. Changing the code so that it only sets the accessibility when the field is not accessible allows applications to get by with serializing classes with only public fields when on servers with this type of security restriction. Also, if you only serialized simple types, String, int etc. you most likely won't have this problem, although I haven't tested this.
Filed under: ajax, google, java, gwt, google web toolkit, tomcat, godaddy
June 21, 2006

gpokr moves to a better neighborhood

It's not easy getting out of the ghetto. Today gpokr is moving on up, off my home machine to a hosted account for $6.99/month.

It didn't work for a while but after digging fairly deap there were security restrictions and the GWT source had to be modified and recompiled for the hosting to work.

Filed under: google, java, poker, gwt, google web toolkit, texas holdem, tomcat
June 20, 2006

Poker in the Ghetto

Where did gpokr go today? The answer is a string of unlikely events:

  1. The gpokr server is running on my home machine because its a java servlet running on tomcat and I don't have any web server access with tomcat.
  2. Rogers, providing good home internet service, changed my IP address after years with the same one. Causing my dynamic domain redirection service no-ip to point to the wrong place.
  3. The point of dynamic redirection services are to update the ip address for a domain dynamically when it changes. But not today. Upon logging to to my no-ip account I see this message:

    2006/06/20, 09:17 AM : Updating hosts for Free and Enhanced services is temporarily disabled due to a small outage. It should be available again in the next few minutes. There is no need to resubmit your updates, they will go through as soon as this is rectified.

    A few minutes turned into several hours.

Its back up but the situation is so ghetto. Lets get gpokr out of the ghetto. Please recommend a good tomcat host. 

Filed under: Uncategorized, java, poker, gwt, google web toolkit, texas holdem, tomcat