All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.relation.accesspath.ChunkConsumerIterator Maven / Gradle / Ivy

package com.bigdata.relation.accesspath;

import java.util.Arrays;
import java.util.NoSuchElementException;

import org.apache.log4j.Logger;

import com.bigdata.striterator.IChunkedOrderedIterator;
import com.bigdata.striterator.IKeyOrder;

import cutthecrap.utils.striterators.ICloseableIterator;

/**
 * A class that aligns a buffer of E[]s (a buffer of chunks) with
 * an {@link IChunkedOrderedIterator}.
 * 
 * @author Bryan Thompson
 * @version $Id: ChunkConsumerIterator.java 6130 2012-03-15 10:31:25Z
 *          thompsonbry $
 * @param 
 * 
 * @see 
 *      Eliminate unnecessary dechunking and rechunking 
 */
public class ChunkConsumerIterator implements IChunkedOrderedIterator {

    final protected static Logger log = Logger.getLogger(ChunkConsumerIterator.class);

    /**
     * True iff the {@link #log} level is INFO or less.
     */
    final protected static boolean INFO = log.isInfoEnabled();

    /**
     * True iff the {@link #log} level is DEBUG or less.
     */
    final protected static boolean DEBUG = log.isDebugEnabled();
    
    /** The source iterator. */
    private final ICloseableIterator src;
    
    /**
     * The order of the elements in the buffer or null iff not
     * known.
     */
    private final IKeyOrder keyOrder;
    
    /**
     * The index of the last entry returned in the current {@link #chunk} and
     * -1 until the first entry is returned.
     */
    private int lastIndex = -1;

    /**
     * The current chunk -or- null if we need to fetch another
     * chunk.
     */
    private E[] chunk = null;
    
//    /**
//     * Total elapsed time for the iterator instance.
//     */
//    private long elapsed = 0L;

    /**
     * #of chunks materialized so far via {@link #nextChunk()} or
     * {@link #nextChunk(IKeyOrder)}.
     */
    private long nchunks = 0L;

    /**
     * #of elements materialized so far.
     */
    private long nelements = 0L;

    /**
     * 
     * @param src
     *            The source iterator. Note that each element visited by the
     *            source iterator is treated as a chunk of elements by this
     *            iterator.
     */
    public ChunkConsumerIterator(final ICloseableIterator src) {

        this(src,/* keyOrder */null);

    }
    
    /**
     * 
     * @param src
     *            The source iterator. Note that each element visited by the
     *            source iterator is treated as a chunk of elements by this
     *            iterator.
     * @param keyOrder
     *            The natural order in which the un-chunked elements in the
     *            source iterator will be visited -or- null if no
     *            known.
     */
    public ChunkConsumerIterator(final ICloseableIterator src,
            final IKeyOrder keyOrder) {

        if (src == null)
            throw new IllegalArgumentException();
        
        this.src = src;
        
        this.keyOrder = keyOrder;
        
    }
    
    public IKeyOrder getKeyOrder() {

        return keyOrder;
        
    }

    public boolean hasNext() {
        
        if ((lastIndex != -1) && ((lastIndex + 1) < chunk.length)) {

            return true;
            
        }
        
        if(DEBUG) {
            
            log.debug("Testing source iterator.");
            
        }
        
        return src.hasNext();
        
    }
    
    public E next() {

        if (!hasNext())
            throw new NoSuchElementException();

        if ((lastIndex == -1) || ((lastIndex + 1) == chunk.length)) {

            // get the next chunk from the source iterator.
            chunk = src.next();
            
            // reset the index.
            lastIndex = -1;

            if (INFO)
                log.info("read chunk from source iterator: nchunks=" + nchunks
                        + ", size=" + chunk.length);

        }

        // the next element.
        final E e = chunk[++lastIndex];
        nelements++;
        
        if (DEBUG)
            log.debug("lastIndex=" + lastIndex + ", chunk.length="
                    + chunk.length + ", #chunks=" + nchunks + ", #elements="
                    + nelements + ", e=" + e);

//        elapsed += (System.currentTimeMillis() - begin);

        return e;
        
    }

    @SuppressWarnings("unchecked")
    public E[] nextChunk() {
        
        if ((lastIndex == -1) || ((lastIndex + 1) == chunk.length)) {

            /*
             * The next element from the source will be the next chunk.
             */

            final E[] a = src.next();
            
            nchunks++;
            nelements += a.length;

            if (INFO)
                log.info("read chunk from source iterator: nchunks=" + nchunks
                        + ", size=" + a.length);
            
            return a;
            
        }
        
        /*
         * There is a partly consumed chunk on hand so we make it dense and
         * return everything remaining in that chunk.
         */
        
        // index of the next element to be returned.
        final int index = lastIndex + 1;
        
        final int remaining = chunk.length - index;
        
        // Dynamic type instantiation of array.
        final E[] a = (E[]) java.lang.reflect.Array.newInstance(
//                chunk[lastIndex + 1].getClass(),
                chunk.getClass().getComponentType(),
                remaining);
        
        // Copy remaining elements.
        System.arraycopy(chunk, index, a, 0, remaining);
        
        // chunk has been consumed.
        chunk = null;
        lastIndex = -1;
        nchunks++;
        nelements += remaining;

        if (INFO)
            log.info("remainder chunk: nchunks=" + nchunks + ", size="
                    + remaining);

        // return dense chunk.
        return a;
        
    }

    public E[] nextChunk(final IKeyOrder keyOrder) {

        if (keyOrder == null)
            throw new IllegalArgumentException();

        final E[] chunk = nextChunk();

        if (!keyOrder.equals(getKeyOrder())) {

            // sort into the required order.

            Arrays.sort(chunk, 0, chunk.length, keyOrder.getComparator());

        }

        return chunk;

    }

    public void remove() {

        throw new UnsupportedOperationException();
        
    }

    public void close() {
    
        src.close();
        
        chunk = null;
        
        if (INFO)
            log.info("#chunks="+nchunks+", #elements="+nelements);
//            log.info("elapsed=" + elapsed);

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy