package com.bigdata.service.proxy;
import java.io.IOException;
import org.apache.log4j.Logger;
import com.bigdata.io.IStreamSerializer;
import com.bigdata.relation.accesspath.IAsynchronousIterator;
import com.bigdata.striterator.IKeyOrder;
/**
* Wrapper for an {@link IAsynchronousIterator} exposing an interface suitable
* for export as a proxy object using RMI to communicate back with itself and
* pull data efficiently from the source iterator.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id$
* @param <E>
* The generic type of the component elements visited by the source
* iterator.
*/
public class RemoteChunkedIterator<E> implements IRemoteChunkedIterator<E> {
protected static final transient Logger log = Logger
.getLogger(RemoteChunkedIterator.class);
protected static final boolean INFO = log.isInfoEnabled();
protected static final boolean DEBUG = log.isDebugEnabled();
private final IAsynchronousIterator<E[]> sourceIterator;
private final IStreamSerializer<E[]> serializer;
private final IKeyOrder<E> keyOrder;
transient volatile boolean open = true;
/**
*
* @param sourceIterator
* The source iterator.
* @param serializer
* The object that will be used to (de-)serialize the elements.
* @param keyOrder
* The natural order of the visited elements if known and
* otherwise <code>null</code>.
*/
public RemoteChunkedIterator(
final IAsynchronousIterator<E[]> sourceIterator,
final IStreamSerializer<E[]> serializer,
final IKeyOrder<E> keyOrder
) {
if (sourceIterator == null)
throw new IllegalArgumentException();
if (serializer == null)
throw new IllegalArgumentException();
this.sourceIterator = sourceIterator;
this.serializer = serializer;
this.keyOrder = keyOrder;
if (DEBUG) {
log.debug("sourceIterator=" + sourceIterator + ", serializer="
+ serializer);
}
}
/*
* Commented out finalize() since the presence of this method can lead to GC
* problems, and we create a LOT of instances of this method.
*/
//
// /**
// * Note: since [keepAlive := false], this appears to be sufficient to force
// * the proxy to be unexported and force the source iterator to be closed.
// */
// protected void finalize() throws Throwable {
//
// if(open) {
//
// log.warn("Closing iterator");
//
// close();
//
// }
//
// super.finalize();
//
// }
/**
* Close the source iterator.
*/
public void close() throws IOException {
if (open) {
if (INFO) {
log.info("Closing iterator.");
}
try {
sourceIterator.close();
} finally {
open = false;
}
}
}
/**
* Return the next {@link IRemoteChunk} from the source iterator. If it
* is exhausted then return an {@link IRemoteChunk} which indicates that
* no more results are available.
*/
public IRemoteChunk<E> nextChunk() throws IOException {
final IRemoteChunk<E> chunk;
if (!sourceIterator.hasNext()) {
if (INFO) {
log.info("nchunks=" + nchunks + " : source is exhausted");
}
chunk = new RemoteChunk<E>(true/* exhausted */, serializer,
keyOrder, null);
} else {
// // @todo config timeout.
// final E[] a = sourceIterator instanceof IAsynchronousIterator//
// ? ((IAsynchronousIterator<E>) sourceIterator).nextChunk(//
// 1000,// minChunkSize
// 1000L, // timeout
// TimeUnit.MILLISECONDS// unit
// )//
// : sourceIterator.nextChunk()//
// ;
final E[] a = sourceIterator.next();
/*
* FIXME This forces us to wait until there is another chunk
* materialized and waiting in the BlockingBuffer's queue or until
* the future is done while the queue is empty. That means that we
* really wait for two chunks to be ready rather than returning when
* the first chunk is available.
*
* Change the RemoteChunk semantics to have the flag indicate only
* whether the iterator is KNOWN to be exhausted. When not known to
* be exhausted the caller must verify whether or not additional
* chunks are available by making another RMI request.
*/
final boolean sourceExhausted = !sourceIterator.hasNext();
if (INFO) {
log.info("nchunks=" + nchunks + ", elementsInChunk=" + a.length
+ ", sourceExhausted=" + sourceExhausted);
}
chunk = new RemoteChunk<E>(sourceExhausted, serializer, keyOrder, a);
}
nchunks++;
return chunk;
}
private transient long nchunks = 0L;
}