// Copyright (c) 2004 Dustin Sallings <dustin@spy.net>
package net.spy.db;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import net.spy.SpyObject;
import net.spy.concurrent.TrackingScheduledExecutor;
import net.spy.util.SpyConfig;
/**
* Asynchronous Saver.
*/
public class TransactionPipeline extends SpyObject {
// Thread pool name
private static final String POOL_NAME="TransactionPipeline Worker";
// Default size of the transaction pipeline pool
private static final int DEFAULT_POOL_SIZE=1;
// Minimum amount of time (in milliseconds) a transaction has to have been
// in the pipeline before it will be considered for processing
private static final int MIN_TRANS_AGE=500;
// The thread pool.
private ScheduledExecutorService pool;
/**
* Get an instance of TransactionPipeline.
*
* @param tg the thread group under which threads will be created
* @param name an optional suffix to the names of the worker created
*/
public TransactionPipeline(ThreadGroup tg, String name) {
super();
final String n=POOL_NAME+(name==null?"": " " + name);
pool=new TrackingScheduledExecutor(DEFAULT_POOL_SIZE, tg, n);
}
/**
* Get a transaction pipeline with no specific name.
*/
public TransactionPipeline() {
this(null, null);
}
/**
* Shut down the pipeline.
*/
public synchronized void shutdown() {
assert pool != null : "Trying to double-shutdown a pool.";
pool.shutdown();
pool = null;
}
/**
* Add a transaction to the pipeline.
*
* @param s the savable
* @param conf the configuration
* @param context a context for the save
*/
public ScheduledFuture<?> addTransaction(
Savable s, SpyConfig conf, SaveContext ctx) {
return pool.schedule(new PipelineTask(s, conf, ctx), MIN_TRANS_AGE,
TimeUnit.MILLISECONDS);
}
/**
* Add a transaction to the pipeline without a context.
*
* @param s the savable
* @param conf the configuration
*/
public ScheduledFuture<?> addTransaction(Savable s, SpyConfig conf) {
return addTransaction(s, conf, null);
}
static final class PipelineTask extends SpyObject
implements Runnable {
// Throwable filled in with the stack holding the context of where the
// pipeline request was original requested
private Throwable originalStack=null;
private Savable toSave=null;
private SpyConfig conf=null;
private SaveContext context=null;
PipelineTask(Savable s, SpyConfig cnf, SaveContext ctx) {
super();
this.originalStack=new Exception("Original request");
originalStack.fillInStackTrace();
this.toSave=s;
conf=cnf;
context=ctx;
}
/**
* Run the transaction.
*/
public void run() {
try {
new Saver(conf, context).save(toSave);
} catch(Throwable t) {
getLogger().error("Error saving asynchronous transaction", t);
getLogger().error("Sent from", originalStack);
}
} // run()
} // class PipelineTask
} // class TransactionPipeline