Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

Rationale for a Delta Session Replication Approach

The "standard" replication approach for HttpSessions consists of serializing sessions as a whole and sending them to other nodes for re-instantiation. Even if this approach is reasonable for web solutions having small session size, it can be quite resource expensive for solutions having large session size.

An approach more effective for such solutions could be to only replicate the modifications made against the objects, i.e. state, stored in sessions. This approach is implemented by wadi-aop.

Here are the steps to follow for this approach:

  1. Identify the types stored in session;
  2. Annotate these types so that wadi-aop can identify the types to be instrumented so that modifications can be tracked at a field or method level;
  3. Apply the aspect defined by wadi-aop to your types; and
  4. Wire in the relevant WADI components for delta replication.

Identify the types stored in session

As of this writing, WADI does not provide any helpers to help in the identification of the types stored in sessions. Having said that, if you already know that your sessions are big, then you should already have a good idea of which types have a large memory footprint.

Annotate the types for intrumentation

Let's assume that you have identified the type MyBigClass as a large object. You need to add the @ClusteredState type annotation to it and, via the trackingLevel attribute of @ClusteredState, specify how you would like modifications to this type to be tracked. There are three ways to track changes:

  • At the field level: when non-transient fields are updated;
  • At the method level: when methods annotated with @TrackedMethod are executed; or
  • Both: combination of above approaches.

The approach you should use really depends on the type to be instrumented.

Type having a Simple Internal Structure - Field Level Tracking

If the type has a rather straight forward internal structure, i.e. simple fields, then the field level tracking is judicious. For example:

Code Block
titleMyBigClass.java
@ClusteredState
public class MyBigClass {
    private String name;
    private MyBigClass child;

    public MyBigClass() {}
}

In the above example, updates to name or child are tracked and are re-played against the replicas of MyBigClass instances.

Type having a Complex Internal Structure - Method Level Tracking

If the type has a rather complex internal structure, then the method level tracking is more judicious. For example:

Code Block
titleMyBigClass.java
@ClusteredState(trackingLevel=TrackingLevel.METHOD)
public class MyBigClass {
    private final Map attributes;
    private MyBigClass child;
    
    public MyBigClass() {
        attributes = new HashMap();
    }
    
    @TrackedMethod
    public void setChild(MyBigClass child) {
        this.child = child;
    }
    
    @TrackedMethod
    public void clear() {
        attributes.clear();
    }

    @TrackedMethod
    public Object put(Object key, Object value) {
        return attributes.put(key, value);
    }

    @TrackedMethod
    public Object remove(Object key) {
        return attributes.remove(key);
    }

    public Object get(Object key) {
        return delegate.get(key);
    }
}

In the above example, execution of setChild, clear, put, remove are tracked and are re-played against the replicas of MyBigClass instances.

Mix of Simple and Complex Internal Structures - Mixed Level Tracking

The combined tracking level is now clear:

Code Block
titleMyBigClass.java
@ClusteredState(trackingLevel=TrackingLevel.MIXED)
public class MyBigClass {
    private Map attributes;
    private MyBigClass child;
   public MyBigClass() {
        attributes = new HashMap();
    }
    public void setChild(MyBigClass child) {
        this.child = child;
    }
    @TrackedMethod
    public void clear() {
        attributes.clear();
    }
    @TrackedMethod
    public Object put(Object key, Object value) {
        return attributes.put(key, value);
    }

    @TrackedMethod
    public Object remove(Object key) {
        return attributes.remove(key);
    }
    public Object get(Object key) {
        return delegate.get(key);
    }
}

In the above example, we do not need to track the execution of setChild, as it was done for the method level tracking, as updates to the field child are already tracked.

Constraints on Annotated Types

There are a couple of constraints to remember about the annotated types:

  • they must have a no-arg constructor as their replicas are instantiated via the Class.newInstance() construct.

Less Intrusive Way to Annotate your Types

If you do not want or can annotate the types stored in session, you can easily "externalize" their annotations by implementing AspectJ aspects defining inter-type declarations of annotations.

For example, if you want to annotate all the types in the package org.codehaus.xyz, then you can implement the following aspect

Code Block
import org.codehaus.wadi.aop.annotation.ClusteredState;
import org.codehaus.wadi.aop.annotation.TrackingLevel;

public aspect MyAspect {

    declare @type:
        org.codehaus.xyz..* : @ ClusteredState(trackingLevel=TrackingLevel.FIELD);
    
}

It is also quite easy to annotate a given method with @TrackedMethod:

Code Block
import org.codehaus.wadi.aop.annotation.ClusteredState;
import org.codehaus.wadi.aop.annotation.TrackingLevel;

public aspect MyAspect {

    declare @type:
        org.codehaus.xyz..* : @ ClusteredState(trackingLevel=TrackingLevel.MIXED);

    declare @method:
        * org.codehaus.xyz.MyType.myMethod(..) : @TrackedMethod;
    
}

Apply the wadi-aop Aspects to your Types

You need to apply the aspectJ aspects defined by wadi-aop to your types. This is done through the standard AspectJ mechanism.

Enable delta replication by wiring the relevant WADI components

Please refer to the Jetty or Geronimo configuration instructions for more details.