Tuesday, December 21, 2004

Modify poolit FixedPooler class to not give null objects on resize

Pool it from acent phase http://www.ascent-phase.org/projects/poolit/ had a good object pooling library. I wanted to use the library for on of my projects, specifically i wanted to use the FixedPooler class http://www.ascent-phase.org/projects/poolit/api/org/ascentphase/poolit/poolers/FixedPooler.html.

FixedPooler has a resize method that i desired to use.

resize

public void resize(int newsize)
Changes the size of the pool. If the new size is smaller than the current, the number of objects exceeding the new size will be discarded. If the new size is greater than the current, the objects currently pooled will be moved over to the new pool, but no new objects will be created to fill in the new space.


Parameters:
newsize - the new size of the poo
So as seen above it does resize the pool as i wanted. But it did not add any new objects to the resized pool.

It uses an array to store objects internally and also there is a pointer called availablepos which is an int, that keeps track of which is the next object to fetch.

Please keep in mind that an array of size one, means that there can be a value at position 0. In other words Array positions start at 0.

For example. consider this pool(Array intenally)
Lets say the pool consists of string values of "A"
{"A","A","A"}
So here the pool size is 3 and the availablepos is 2.

A call to the fetch method will do this.
{"A","A",null}
So now the pool size is 2 and the availablepos is 1.

one more call to fetch will do this
{"A",null,null}
So now the pool size is 1 and the availablepos is 0.

one more call to fetch will do this
{null,null,null}
So now the pool size is 0 and the availablepos is -1.

How does this affect resize.

Lets say we are in this position:
{"A",null,null}
The pool size is 1 and the availablepos is 0.

Now someone issues a resize to be 6 by calling pool.resize(6)
So what will happen is
{"A",null,null, null,null,null}

The logical uestion is why can it not be
{"A",null,null, "A","A","A"}, that is the new Array gets the default objects in the pool ?

Look at the value of availablepos, it is 0, how ill that move to the new values as still at position 0 there is a value. Also the way to copy arrays in java is System.arraycopy(), and that does the copy exactly as descibed above, copies the values from the old array to the new array.

How do we solve this ?

I wrote a class that i called ModifiedFixedPooler which operates just like the Fixed pooler by pool it. But it handles the availablepos pointer differently.

Let's consider the same example
Lets say the pool consists of string values of "A"
{"A","A","A"}
So now here the pool size is 3 and the availablepos is O.

A call to the fetch method will do this.
{null,"A","A"}
So now the pool size is 2 and the availablepos is 1.

one more call to fetch will do this
{null,null,"A"}
So now the pool size is 1 and the availablepos is 2.

one more call to fetch will do this
{null,null,null}
So now the pool size is 0 and the availablepos is 3.

How does help the resize.

Lets say we are in this position:
{null,null,"A"}
So now the pool size is 1 and the availablepos is 2.

Now someone issues a resize to be 6 by calling pool.resize(6)
So what will in my method is this
{null,null,"A", "A","A","A"}
So now the pool size is 4 and the availablepos is still 2 which is right and does not need to change.

You can get the source code for fixed pooler at http://www.ascent-phase.org/downloads.php.

I am typing in the source code for the modified fixed pooler here.

/*
* Created on March 21, 2004
*/
package com.test.poolit;

/*
* @author suchakj
*/
import org.ascentphase.poolit.CreateException;
import org.ascentphase.poolit.FetchException;
import org.ascentphase.poolit.PoolHandler;
import org.ascentphase.poolit.Pooler;
import org.ascentphase.poolit.handlers.NoArgHandler;
import org.ascentphase.poolit.poolers.FixedPooler;

public class ModifiedFixedPooler implements Pooler {
protected Object pool[];
protected PoolHandler handler;
/**
* Points to the index in the pool array where the next available object
* can be retrieved from.
*/
protected int availPos;

/**
* Creates a pool with the specified class and size.
*
* @param name class to be pooled
* @param size size of pool to be created
*/
public ModifiedFixedPooler(Class name, int size) throws CreateException {
this(new NoArgHandler(name), size);
}

/**
* Creates a pool using the specified handler and size.
*
* @param handler PoolHandler to be used by this pool
* @param size size of pool to be created
*/
public ModifiedFixedPooler(PoolHandler handler, int size) throws CreateException {
this.handler = handler;
this.pool = new Object[size];
this.availPos = size;
fillPool();
}

public synchronized Object fetch() throws FetchException {
Object objret = null;

do {
if (availPos <>
objret = pool[availPos];
// remove reference in case object is not returned to pool
// so it can be garbage collected
pool[availPos++] = null;
if (!handler.verify(objret)) {
handler.destroy(objret);
objret = null;
}
} else { // no more objects available in pool
try {
objret = handler.create();
} catch (CreateException e) {
throw new FetchException(e.toString());
}
}
} while (objret == null);
//logx.info("availPos :: " + availPos);
return objret;
}

public synchronized void release(Object o) {
if (o == null) {
throw new NullPointerException();
} else if (availPos!=0 && availPos <= pool.length) {
pool[--availPos] = o;
} else { // pool full, so prepare object to be garbage collected
handler.destroy(o);
}
}

/**
* Reports the number of objects currently in the pool.
*
* @return the number of objects in the pool
*/
public int size() {
return pool.length - availPos;
}

/**
* Reports the maximum number of objects this pool can contain.
*
* @return the capacity of the pool
*/
public int capacity() {
return pool.length;
}

/**
* Changes the size of the pool.
* If the new size is smaller than the current, the number of objects
* exceeding the new size will be discarded.
* If the new size is greater than the current, the objects currently
* pooled will be moved over to the new pool, and new objects will be
* created to fill in the new space.
*
* @param newsize the new size of the pool
*/
public synchronized void resize(int newsize) {
if (newsize != capacity()) {
Object newpool[] = new Object[newsize];
// if newsize is smaller than # of current available objects, then
// copy upto newsize
int tempsize = pool.length;
if (newsize <>
System.arraycopy(pool, 0, newpool, 0, newsize);
// any objects not moved over to new pool are to be destroyed
// Which is ok as the size has to be shrunk or reduced
while (tempsize!=newsize){
handler.destroy(pool[--tempsize]);
}
// set next available object to first element in array
//availPos = newsize - 1;
} else { // copy up to available # of objects
int filllength=newpool.length-pool.length;
int currentfillpos = pool.length;
System.arraycopy(pool, 0, newpool, 0, currentfillpos);
// no need to change availPos value

for (int i=0; i
try {
newpool[currentfillpos] = handler.create();
} catch (CreateException e) {

e.printStackTrace();
}
++currentfillpos;
}
}

pool = newpool;
}
}

/**
* Called by constructor to fill up the pool.
*/
protected void fillPool() throws CreateException {
for (int i=0; i
availPos--;
pool[availPos] = handler.create();
//--availPos;
}
}

/**
* Destroys all objects in the pool.
* Implicitly, the next call to the fetch() will force a call to the
* handler's create() method.
*
* @see org.ascentphase.poolit.Pooler#close()
*/
public synchronized void close() {
while (availPos <>
handler.destroy(pool[availPos]);
pool[availPos] = null;
++availPos;
}
}

public static void main(String[] args) {

try {
ModifiedFixedPooler this_ = new ModifiedFixedPooler(String.class, 10);
this_.fetch();
this_.resize(20);

FixedPooler this_original = new FixedPooler(String.class,10);
this_original.fetch();
this_original.resize(20);
} catch (CreateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FetchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

0 Comments:

Post a Comment

<< Home