Package lupos.engine.operators.multiinput.join.parallel

Source Code of lupos.engine.operators.multiinput.join.parallel.ParallelJoin$QueryResultMaterializer

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
*
*/
package lupos.engine.operators.multiinput.join.parallel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import lupos.datastructures.bindings.Bindings;
import lupos.datastructures.parallel.BoundedBuffer;
import lupos.datastructures.queryresult.ParallelIteratorMultipleQueryResults;
import lupos.datastructures.queryresult.QueryResult;
import lupos.datastructures.queryresult.QueryResultDebug;
import lupos.engine.operators.Operator;
import lupos.engine.operators.OperatorIDTuple;
import lupos.engine.operators.messages.EndOfEvaluationMessage;
import lupos.engine.operators.messages.Message;
import lupos.engine.operators.multiinput.MultiInputOperator;
import lupos.engine.operators.multiinput.join.HashFunction;
import lupos.engine.operators.multiinput.join.Join;
import lupos.misc.debug.DebugStep;

public class ParallelJoin extends Join {

  // contains all ParallelJoiner-threads
  private static ThreadGroup toJoinBeforeNewQuery = new ThreadGroup(
      "toJoinBeforeNewQuery");
  // the number of ParallelJoiner-threads started
  private static int number = 0;

  private static final long serialVersionUID = 1L;

  protected static int DEFAULT_NUMBER_THREADS = 8;

  protected static int MAXBUFFER = 50;

  private static final int LEFT = 0;

  private static final int RIGHT = 1;

  protected ParallelIteratorMultipleQueryResults[] operands = new ParallelIteratorMultipleQueryResults(),
                                  new ParallelIteratorMultipleQueryResults()};

  protected final Collection<? extends MultiInputOperator> operators;

  protected ResultCollector col;

  private EndOfEvaluationMessage endOfStreamMsg;

  private final HashFunction hashFun;

  private final List<ParallelJoiner> threadList;

  private final boolean optional;

  public ParallelJoin(
      final Collection<? extends MultiInputOperator> operators,
      final boolean optional) {
    this(operators, new ResultCollector(), optional);
  }

  public ParallelJoin(
      final Collection<? extends MultiInputOperator> operators,
      final ResultCollector col, final boolean optional) {
    this.operators = operators;
    this.col = col;
    for (final MultiInputOperator join : operators) {
      join.setSucceedingOperator(new OperatorIDTuple(col, 0));
    }
    this.hashFun = new HashFunction();
    this.threadList = new ArrayList<ParallelJoiner>(operators.size());
    this.optional = optional;
  }

  public static void waitForJoinThreads() {
    final Thread[] threads = new Thread[ParallelJoin.toJoinBeforeNewQuery
        .activeCount()];
    ParallelJoin.toJoinBeforeNewQuery.enumerate(threads, false);
    for (final Thread t : threads) {
      try {
        t.join();
      } catch (final InterruptedException e) {
        System.err.println();
        e.printStackTrace();
      }
    }

  }

  @Override
  public synchronized QueryResult process(final QueryResult queryResult,
      final int operatorID) {
    this.operands[operatorID].addQueryResult(queryResult);
    return null;
  }

  @Override
  public Message preProcessMessage(final EndOfEvaluationMessage msg) {
    this.endOfStreamMsg = msg;
    if (!this.operands[0].isEmpty() && !this.operands[1].isEmpty()) {
      final QueryResult qr = join();
      if (qr != null) {
        if (this.succeedingOperators.size() > 1)
          qr.materialize();
        for (final OperatorIDTuple opId : this.succeedingOperators) {
          opId.processAll(qr);
        }
      }
    }
    this.operands[0].release();
    this.operands[1].release();
    this.operands[0] = new ParallelIteratorMultipleQueryResults();
    this.operands[1] = new ParallelIteratorMultipleQueryResults();
    return msg;
  }

  @Override
  public Message preProcessMessageDebug(final EndOfEvaluationMessage msg, final DebugStep debugstep) {
    this.endOfStreamMsg = msg;
    if (!this.operands[0].isEmpty() && !this.operands[1].isEmpty()) {
      final QueryResult qr = join();
      if (qr != null) {
        if (this.succeedingOperators.size() > 1)
          qr.materialize();
        for (final OperatorIDTuple opId : this.succeedingOperators) {
          final QueryResultDebug qrDebug = new QueryResultDebug(qr,
              debugstep, this, opId.getOperator(), true);
          ((Operator) opId.getOperator()).processAllDebug(qrDebug,
              opId.getId(), debugstep);
        }
      }
    }
    this.operands[0].release();
    this.operands[1].release();
    this.operands[0] = new ParallelIteratorMultipleQueryResults();
    this.operands[1] = new ParallelIteratorMultipleQueryResults();
    return msg;
  }

  /**
   * the actual join
   */
  protected QueryResult join() {
    // compute intersection variables
    // number of threads is minimum of the number of operators or left or
    // right size

    final int numberOfThreads = /* Math.min( */
    this.operators.size()
    /*
     * , Math.min(left // this forces the query results to materialize => do
     * not do this! .size(), right.size()))
     */;
    this.threadList.clear();

    // if nothing to join
    if (numberOfThreads == 0) {
      return null;
    }
    // create Queryresults

    // relate each binding to one of the right results
    // the key of the hashfunktion should be in the bound of the
    // Threadsnumber
    // every arraycell has a list of bindings
    final QueryResult[] leftResults = prepareResultArray(numberOfThreads, this.operands[0].getQueryResult());
    final QueryResult[] rightResults = prepareResultArray(numberOfThreads, this.operands[1].getQueryResult());

    int countThreads = 0;
    final Iterator<? extends MultiInputOperator> iterator = this.operators.iterator();
    if (this.optional) {
      // optional anyway materializes its queryresults
      // so do this before, because we want to know the number of results!
      final QueryResultMaterializer[] qrm_right = new QueryResultMaterializer[rightResults.length];
      final QueryResultMaterializer[] qrm_left = new QueryResultMaterializer[leftResults.length];
      for (int i = 0; i < rightResults.length; i++) {
        qrm_right[i] = new QueryResultMaterializer(rightResults[i]);
        qrm_right[i].start();
        qrm_left[i] = new QueryResultMaterializer(leftResults[i]);
        qrm_left[i].start();
      }
      for (int i = 0; i < rightResults.length; i++) {
        try {
          qrm_right[i].join();
          qrm_left[i].join();
        } catch (final InterruptedException e) {
          System.err.println(e);
          e.printStackTrace();
        }
      }
    }
    for (int i = 0; i < rightResults.length; i++) {
      final MultiInputOperator nextOperator = iterator.next();
      if (this.optional) {
        if (rightResults[i].size() == 0) {
          if (leftResults[i].size() > 0)
            this.col.process(leftResults[i], LEFT);
          continue;
        }
      }
      // if the list of the binding is not empty
      // count the number of threads
      countThreads++;
      final ParallelJoiner parallelJoin = new ParallelJoiner(
          leftResults[i], rightResults[i], nextOperator);
      // add the Therads to the list
      this.threadList.add(parallelJoin);
    }
    // before the Threads start, deliver the number of threads to the
    // resultCollector
    this.col.setNumberOfThreads(countThreads);
    // start all Threads
    // System.out.println("Paralleljoin().preprocessMs countThreads: "
    // + countThreads);
    for (int i = 0; i < countThreads; i++) {
      this.threadList.get(i).start();
    }
    return this.col.getResult();
  }

  private QueryResult[] prepareResultArray(final int numberOfThreads,
      final QueryResult source) {

    @SuppressWarnings("unchecked")
    final BoundedBuffer<Bindings>[] buffer = new BoundedBuffer[numberOfThreads];

    final QueryResult[] res = new QueryResult[numberOfThreads];
    for (int i = 0; i < numberOfThreads; i++) {
      buffer[i] = new BoundedBuffer<Bindings>(MAXBUFFER);
      res[i] = QueryResult.createInstance(buffer[i]);
    }

    new BindingsSharerThread(buffer, source).start();
    return res;
  }

  public static int getDEFAULT_NUMBER_THREADS() {
    return DEFAULT_NUMBER_THREADS;
  }

  public static void setDEFAULT_NUMBER_THREADS(
      final int default_number_threads) {
    DEFAULT_NUMBER_THREADS = default_number_threads;
  }

  public static int getMAXBUFFER() {
    return MAXBUFFER;
  }

  public static void setMAXBUFFER(final int maxbuffer) {
    MAXBUFFER = maxbuffer;
  }

  protected class ParallelJoiner extends Thread {

    private final QueryResult left;

    private final QueryResult right;

    private final MultiInputOperator joiner;

    public ParallelJoiner(final QueryResult left, final QueryResult right,
        final MultiInputOperator joinOperator) {
      super(toJoinBeforeNewQuery, "ParallelJoiner" + (number++));
      this.left = left;
      this.right = right;
      this.joiner = joinOperator;
    }

    public MultiInputOperator getJoiner() {
      return this.joiner;
    }

    @Override
    public void run() {
      this.joiner.setIntersectionVariables(ParallelJoin.this.intersectionVariables);
      this.joiner.process(this.left, LEFT);
      // System.out.println("ParallelJoiner.run()leftsize: " + left.size()
      // + " rightsize: " + right.size());
      final QueryResult res = this.joiner.process(this.right, RIGHT);
      if (res != null) {
        ParallelJoin.this.col.process(res, LEFT);
      }
      ParallelJoin.this.endOfStreamMsg = (EndOfEvaluationMessage) this.joiner.preProcessMessage(ParallelJoin.this.endOfStreamMsg);
      ParallelJoin.this.col.incNumberOfThreads();
      // System.out.println("ParallelJoiner.run() end");

    }
  }

  /**
   * Shares the bindings to the threads
   *
   */
  public class BindingsSharerThread extends Thread {

    private final BoundedBuffer<Bindings>[] b;

    private final QueryResult qres;

    /**
             *
             */
    public BindingsSharerThread(final BoundedBuffer<Bindings>[] b,
        final QueryResult qres) {
      this.b = b;
      this.qres = qres;

    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Thread#run()
     */
    @Override
    public void run() {
      try {
        shareOut();
      } catch (final InterruptedException e) {
        e.printStackTrace();
      }

    }

    /**
     * @throws InterruptedException
     *
     */
    private void shareOut() throws InterruptedException {
      final long numberOfThreads = this.b.length;
      final BoundedBuffer<Bindings>[] leftBuff = this.b;
      final Iterator<Bindings> leftIter = this.qres.oneTimeIterator();
      // share the rest of the bindings
      while (leftIter.hasNext()) {// share left
        final Bindings bindings = leftIter.next();
        if (bindings != null) {
          final long key = ParallelJoin.this.hashFun.hash(HashFunction.getKey(bindings, ParallelJoin.this.intersectionVariables));
          final int resultNumber = (int) (key % numberOfThreads);
          leftBuff[resultNumber].put(bindings);
        }
      }
      // now all bindings are shared out!
      for (int i = 0; i < numberOfThreads; i++) {
        leftBuff[i].endOfData();
      }
    }
  }

  public class QueryResultMaterializer extends Thread {

    private final QueryResult qres;

    /**
             *
             */
    public QueryResultMaterializer(final QueryResult qres) {
      this.qres = qres;

    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Thread#run()
     */
    @Override
    public void run() {
      this.qres.materialize();
    }
  }
}
TOP

Related Classes of lupos.engine.operators.multiinput.join.parallel.ParallelJoin$QueryResultMaterializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.