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

com.bigdata.striterator.AbstractChunkedResolverator Maven / Gradle / Ivy

/*

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     [email protected]

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/
package com.bigdata.striterator;

import java.nio.channels.ClosedByInterruptException;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;

import org.apache.log4j.Logger;

import com.bigdata.relation.accesspath.BlockingBuffer;
import com.bigdata.relation.accesspath.IAsynchronousIterator;
import com.bigdata.util.InnerCause;

import cutthecrap.utils.striterators.ICloseableIterator;

/**
 * Wraps an {@link IChunkedIterator} and asynchronously resolves chunks.
 * 
 * @author Bryan Thompson
 * @version $Id$
 * 
 * @param 
 *            The generic type of the elements visited by the source iterator.
 * @param 
 *            The generic type of the elements visited by this iterator (the
 *            resolved elements).
 * @param 
 *            The generic type of the application state object.
 */
abstract public class AbstractChunkedResolverator implements ICloseableIterator {

    final private static Logger log = Logger
            .getLogger(AbstractChunkedResolverator.class);

//    /**
//     * True iff the {@link #log} level is DEBUG or less.
//     */
//    final protected static boolean DEBUG = log.isDebugEnabled();
    
    /**
     * The source iterator.
     */
    private final IChunkedOrderedIterator src;
    
    /**
     * Application specified state object.
     */
    protected final S state;
    
    /**
     * 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 of resolved elements.
     */
    private F[] chunk = null;

    private volatile boolean open = true;
    
//    /**
//     * Total elapsed time for the iterator instance.
//     */
//    private long elapsed = 0L;
    
    /**
     * 
     * @param state
     *            Application specified state (optional).
     * @param src
     *            The source iterator (will be closed or exhausted when this
     *            iterator is closed).
     * @param buffer
     *            The {@link BlockingBuffer} on which the resolved chunks will
     *            be written by the {@link ChunkConsumerTask} and from which
     *            this iterator will read those chunks.
     */
    public AbstractChunkedResolverator(final S state,
            final IChunkedOrderedIterator src,
            final BlockingBuffer buffer) {

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

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

        this.state = state;

        this.src = src;

        this.buffer = buffer;
        
    }

    /**
     * Creates and runs a task that will consume chunks from the source
     * iterator, resolve the elements in each chunk, and place the resolved
     * chunks onto the {@link BlockingBuffer}.
     * 

* You MUST invoke this before consuming results from the iterator. *

* Implementations SHOULD strengthen the return type. * * @param service * The service on which the task will be executed. */ // Note: Synchronized for atomic decision making and publication of [resolvedItr]. synchronized public AbstractChunkedResolverator start(final ExecutorService service) { if (resolvedItr != null) throw new IllegalStateException(); /* * Create a task which reads chunks from the source iterator and writes * resolved chunks on the buffer. */ final FutureTask ft = new FutureTask( new ChunkConsumerTask()); /* * Set the future for that task on the buffer. */ buffer.setFuture(ft); /* * This class will read resolved chunks from the [resolvedItr] and then * hand out BigdataStatements from the current [chunk]. */ resolvedItr = buffer.iterator(); // Submit the task for execution. service.execute(ft); // /* // * Create and run a task which reads chunks from the source iterator and // * writes resolved chunks on the buffer. // */ // final Future f = service.submit(new ChunkConsumerTask()); // // /* // * Set the future for that task on the buffer. // */ // buffer.setFuture(f); return this; } /** * Buffer containing chunks of resolved elements. */ private final BlockingBuffer buffer; /** * Iterator draining chunks of resolved elements from the {@link #buffer}. * This is null until {@link #start(ExecutorService)} is * invoked. */ private IAsynchronousIterator resolvedItr; /** * Consumes chunks from the source iterator, placing the converted chunks on * a queue. * * @author Bryan Thompson */ private class ChunkConsumerTask implements Callable { public ChunkConsumerTask() { } /** * @return The #of elements (not chunks) that were converted. * * @throws Exception */ @Override public Long call() throws Exception { try { if (log.isDebugEnabled()) log.debug("Start"); final long begin = System.currentTimeMillis(); long nchunks = 0; long nelements = 0; // while buffer (aka sink) is open and source has more data. while (buffer.isOpen() && src.hasNext()) { // fetch the next chunk (already available). final E[] chunk = src.nextChunk(); if (!buffer.isOpen()) { /* * Asynchronous close of the sink. By checking * buffer.isOpen() here and in the while() clause, we * will notice a closed sink more rapidly and close * the source in a more timely manner. * * @see https://sourceforge.net/apps/trac/bigdata/ticket/361 */ break; } final F[] converted; try { converted = resolveChunk(chunk); } catch (Throwable t) { /* * If the root cause of the throwable was an interrupt, * then close the buffer (aka the sink) and break out of * the loop (we will not read anything more from the * source). * * @see * https://sourceforge.net/apps/trac/bigdata/ticket/460 */ if (InnerCause.isInnerCause(t, InterruptedException.class) || InnerCause.isInnerCause(t, ClosedByInterruptException.class)) { // buffer.abort(t); buffer.close(); break; } throw new RuntimeException(t); } /** * Note: This is no longer true. Some conversions can now * expand or reduce the size of the chunk. * * @see * Efficient batch remove of a collection of triple * patterns */ // assert converted.length == chunk.length; // Note: Throws BufferClosedException if closed. buffer.add(converted); nchunks++; nelements += chunk.length; if (log.isDebugEnabled()) log.debug("nchunks=" + nchunks + ", chunkSize=" + chunk.length); } final long elapsed = (System.currentTimeMillis() - begin); if (log.isInfoEnabled()) log.info("Finished: nchunks=" + nchunks + ", nelements=" + nelements + ", elapsed=" + elapsed + "ms, sink.open=" + buffer.isOpen()); return nelements; } finally { try { src.close(); } finally { /* * Note: Close the buffer since nothing more will be written * on it, but DO NOT close the iterator draining the buffer * (aka [resolvedItr]) since the consumer will use that to * drain the buffer. * * Note: Failure to close the buffer here will cause a * severe performance penalty. * * Note: Closing the [resolvedItr] here will cause data to * be lost. */ buffer.close(); } } } } /** * Resolves the elements in a source chunk, returning a chunk of resolved * elements. *

* Note: This method is invoked by the {@link ChunkConsumerTask} which runs * asynchronously. * * @param chunk * The next chunk from the source iterator. * * @return The resolved chunk. */ abstract protected F[] resolveChunk(final E[] chunk); /** * @throws IllegalStateException * unless {@link #start(ExecutorService)} has been invoked. */ @Override public boolean hasNext() { if(open && _hasNext()) return true; close(); return false; } private boolean _hasNext() { if (resolvedItr == null) { throw new IllegalStateException(); } if (lastIndex != -1 && chunk != null && lastIndex + 1 < chunk.length) { return true; } // read a resolved chunk from the buffer's async iterator. return resolvedItr.hasNext(); } @Override public F next() { // final long begin = System.currentTimeMillis(); if (!hasNext()) throw new NoSuchElementException(); if (lastIndex == -1 || chunk != null && lastIndex + 1 == chunk.length) { // get the next chunk of resolved BigdataStatements. chunk = resolvedItr.next(); // reset the index. lastIndex = -1; // final long now = System.currentTimeMillis(); // elapsed += (now - begin); if (log.isDebugEnabled()) log.debug("nextChunk ready: size=" + chunk.length + ", chunk=" + Arrays.toString(chunk)); } // the next resolved element. final F f = chunk[++lastIndex]; if (log.isDebugEnabled()) log.debug("lastIndex=" + lastIndex + ", chunk.length=" + chunk.length + ", visting=" + f); return f; } /** * @throws UnsupportedOperationException */ @Override public void remove() { throw new UnsupportedOperationException(); } @Override public void close() { if (open) { open = false; if (log.isInfoEnabled()) log.info("lastIndex=" + lastIndex + ", chunkSize=" + (chunk != null ? "" + chunk.length : "N/A")); /* * Explicitly close the source since we will not be reading anything * more from it. * * @see https://sourceforge.net/apps/trac/bigdata/ticket/361 */ src.close(); /* * Close the sink since nothing more will be written on it. */ buffer.close(); /* * Since the outer iterator is being closed, nothing more will be * read from the buffer so we also close the iterator draining the * buffer. */ resolvedItr.close(); chunk = null; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy