Summary: Using Externalizable to boost remote space performance operations.

Overview

To solve the performance problems associated with a class serialization, the serialization mechanism allows you to declare that a class is Externalizable. When the ObjectOutputStream writeObject() method is called, it performs the following sequence of actions:

  • Tests to see if the object is an instance of Externalizable. If so, it uses externalization to marshall the object.
  • If the object isn't an instance of Externalizable, it tests to see whether the object is an instance of Serializable. If so, it uses serialization to marshall the object. If neither of these two cases apply, an exception is thrown.

Externalizable is an interface that consists of two methods:

public void readExternal(ObjectInput in);
public void writeExternal(ObjectOutput out);

The Externalization mechanism writes out the identity of the class (which boils down to the name of the class and the appropriate serialVersionUID). It also stores the superclass structure and all the information about the class hierarchy. But instead of visiting each superclass and using it to store some of the state information, it simply calls writeExternal() on the local class definition.
The Externalization mechanism stores all the metadata, but writes out only the local instance information.

When using a POJO class with the space API, you may implement the Externalizable mechanism. This can be done to control serialization and deserialization when the Object is sent to the space (e.g. write, update and execute Operations) and when it is sent back to the client (e.g. read and take operations). This will optimize the remote call when using Remote Space configuration for single, partitioned, and replicated space topologies Space Runtime Modes.

Externalizable is supported with the Native Serialization mode.

Example

Space Domain POJO Message Class

Here is a simple POJO class:

Message
package com.j_spaces.examples.benchmark;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import com.gigaspaces.annotation.pojo.*;


@SpaceClass
public class Message {
	private static final long serialVersionUID = 1L;
	
	private byte[] content;
	private Long counter;
	private ArrayList<GregorianCalendar> list;

	public byte[] getContent()
	{
		return content;
	}
	
	public void setContent(byte[] content)
	{
		this.content = content;
		generateData(10);
	}

	@SpaceIndex (type=SpaceIndexType.BASIC)
	Long getCounter()
	{
		return counter;
	}
	
	public void setCounter(Long counter)
	{
		this.counter = counter;
	}
	
	public ArrayList<GregorianCalendar> getList()
	{
		return list;
	}
	public void setList(ArrayList<GregorianCalendar> list)
	{
		this.list = list;
	}

	public Message () {
	}

	public Message (long initVal, byte[] content) {
		content = content;
		counter = initVal;
		if (content !=null)
			generateData(10);
	}

	public void generateData(int capacity) {
		if (capacity > 0) {
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = (int) (Math.random() * 2000);
				int month = (int) (Math.random() * 12);
				int day = (int) (Math.random() * 31);
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}



	@Override
	public String toString() {
		return getClass() + "_" + counter + "_" + content;
	}

}

Space Domain POJO Message Class Implements Externalizable

Here is the same class with the Externalizable interface implemented.
See how the list field that is ArrayList<GregorianCalendar> is serialized and deserialized:

Message
package com.j_spaces.examples.benchmark;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import com.gigaspaces.annotation.pojo.*;

@SpaceClass
public class Message implements Externalizable {
	private static final long serialVersionUID = 1L;

	private byte[] content;
	private Long counter;
	private ArrayList<GregorianCalendar> list;

	public byte[] getContent()
	{
		return content;
	}
	
	public void setContent(byte[] content)
	{
		this.content = content;
		generateData(10);
	}

	@SpaceIndex (type=SpaceIndexType.BASIC)		
	Long getCounter()
	{
		return counter;
	}
	
	public void setCounter(Long counter)
	{
		this.counter = counter;
	}
	
	public ArrayList<GregorianCalendar> getList()
	{
		return list;
	}
	public void setList(ArrayList<GregorianCalendar> list)
	{
		this.list = list;
	}
	
	public Message() {
	}

	public Message(long initVal, byte[] content) {
		content = content;
		counter = initVal;
		if (content !=null)
			generateData(10);
	}

	public void writeExternal(ObjectOutput out) throws IOException {
		if (counter == null)
			out.writeLong(0);
		else
			out.writeLong(counter);
		
		if (content != null )
		{
			out.writeInt(content.length);
			out.write(content ,0, content.length);
		}
		else
		{
			out.writeInt(0);
		}
			
		if (list != null) {
			out.writeBoolean(true);
			out.writeInt(list.size());
			for (GregorianCalendar date : list) {
				out.writeInt(date.get(Calendar.YEAR));
				out.writeInt(date.get(Calendar.MONTH));
				out.writeInt(date.get(Calendar.DAY_OF_MONTH));
			}
		} else {
			out.writeBoolean(false);
		}
	}

	public void readExternal(ObjectInput in) throws IOException,
			ClassNotFoundException {
		counter = (Long) in.readLong();
		Integer content_length =in.readInt(); 
		if (content_length >0) 
		{

			content = new byte[content_length.intValue()];
			in.read(content, 0 , content_length.intValue());
		}
		boolean islist = in.readBoolean();
		if (islist )
		{
			int capacity = (Integer) in.readInt();
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = in.readInt();
				int month = in.readInt();
				int day = in.readInt();
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}

	public void generateData(int capacity) {
		if (capacity > 0) {
			list = new ArrayList<GregorianCalendar>(capacity);
			for (int i = 0; i < capacity; i++) {
				int year = (int) (Math.random() * 2000);
				int month = (int) (Math.random() * 12);
				int day = (int) (Math.random() * 31);
				list.add(i, new GregorianCalendar(year, month, day));
			}
		}
	}


	@Override
	public String toString() {
		return getClass() + "_" + counter + "_" + content;
	}
}

Performance Tests Results

GigaSpaces.com - Legal Notice - 3rd Party Licenses - Site Map - API Docs - Forum - Downloads - Blog - White Papers - Contact Tech Writing - Gen. by Atlassian Confluence