Package org.teiid.dqp.internal.process

Source Code of org.teiid.dqp.internal.process.RequestWorkItem$WorkWrapper

/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.  Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/

package org.teiid.dqp.internal.process;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

import org.teiid.client.RequestMessage;
import org.teiid.client.ResultsMessage;
import org.teiid.client.SourceWarning;
import org.teiid.client.RequestMessage.ShowPlan;
import org.teiid.client.lob.LobChunk;
import org.teiid.client.metadata.ParameterInfo;
import org.teiid.client.util.ResultsReceiver;
import org.teiid.client.xa.XATransactionException;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.TupleBatch;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.common.buffer.BufferManager.TupleSourceType;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.dqp.internal.process.DQPCore.CompletionListener;
import org.teiid.dqp.internal.process.DQPCore.FutureWork;
import org.teiid.dqp.internal.process.SessionAwareCache.CacheID;
import org.teiid.dqp.internal.process.ThreadReuseExecutor.PrioritizedRunnable;
import org.teiid.dqp.message.AtomicRequestID;
import org.teiid.dqp.message.RequestID;
import org.teiid.dqp.service.TransactionContext;
import org.teiid.dqp.service.TransactionService;
import org.teiid.dqp.service.TransactionContext.Scope;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.logging.CommandLogMessage.Event;
import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.parser.ParseInfo;
import org.teiid.query.parser.QueryParser;
import org.teiid.query.processor.BatchCollector;
import org.teiid.query.processor.QueryProcessor;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.SPParameter;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.symbol.SingleElementSymbol;

public class RequestWorkItem extends AbstractWorkItem implements PrioritizedRunnable {
 
  private final class WorkWrapper<T> implements
      DQPCore.CompletionListener<T> {
   
    boolean submitted;
    FutureWork<T> work;
   
    public WorkWrapper(FutureWork<T> work) {
      this.work = work;
    }

    @Override
    public void onCompletion(FutureWork<T> future) {
      WorkWrapper<?> nextWork = null;
      synchronized (queue) {
        if (!submitted) {
          return;
        }
        nextWork = queue.pollFirst();
        if (nextWork == null) {
          totalThreads--;
        } else {
          nextWork.submitted = true;
        }
      }
      if (nextWork != null) {
        dqpCore.addWork(nextWork.work);
      }       
    }
  }

  private enum ProcessingState {NEW, PROCESSING, CLOSE}
  private ProcessingState state = ProcessingState.NEW;
   
  private enum TransactionState {NONE, ACTIVE, DONE}
  private TransactionState transactionState = TransactionState.NONE;
 
  private int totalThreads;
  private LinkedList<WorkWrapper<?>> queue = new LinkedList<WorkWrapper<?>>();
 
  /*
   * Obtained at construction time
   */
  protected final DQPCore dqpCore;
    final RequestMessage requestMsg;   
    final RequestID requestID;
    private Request request; //provides the processing plan, held on a temporary basis
    private final int processorTimeslice;
  private CacheID cid;
  private final TransactionService transactionService;
  private final DQPWorkContext dqpWorkContext;
  boolean active;
 
    /*
     * obtained during new
     */
    private volatile QueryProcessor processor;
    private BatchCollector collector;
    private Command originalCommand;
    private AnalysisRecord analysisRecord;
    private TransactionContext transactionContext;
    TupleBuffer resultsBuffer;
    private boolean returnsUpdateCount;
   
    /*
     * maintained during processing
     */
    private Throwable processingException;
    private Map<AtomicRequestID, DataTierTupleSource> connectorInfo = new ConcurrentHashMap<AtomicRequestID, DataTierTupleSource>(4);
    // This exception contains details of all the atomic requests that failed when query is run in partial results mode.
    private List<TeiidException> warnings = new LinkedList<TeiidException>();
    private volatile boolean doneProducingBatches;
    private volatile boolean isClosed;
    private volatile boolean isCanceled;
    private volatile boolean closeRequested;

  //results request
  private ResultsReceiver<ResultsMessage> resultsReceiver;
  private int begin;
  private int end;
    private TupleBatch savedBatch;
    private Map<Integer, LobWorkItem> lobStreams = new ConcurrentHashMap<Integer, LobWorkItem>(4);   
   
    /**The time when command begins processing on the server.*/
    private long processingTimestamp = System.currentTimeMillis();
   
    public RequestWorkItem(DQPCore dqpCore, RequestMessage requestMsg, Request request, ResultsReceiver<ResultsMessage> receiver, RequestID requestID, DQPWorkContext workContext) {
      super(workContext.useCallingThread() || requestMsg.isSync());
        this.requestMsg = requestMsg;
        this.requestID = requestID;
        this.processorTimeslice = dqpCore.getProcessorTimeSlice();
        this.transactionService = dqpCore.getTransactionService();
        this.dqpCore = dqpCore;
        this.request = request;
        this.dqpWorkContext = workContext;
        this.requestResults(1, requestMsg.getFetchSize(), receiver);
    }
   
    private boolean isForwardOnly() {
      return this.cid == null && requestMsg.getCursorType() == ResultSet.TYPE_FORWARD_ONLY;     
    }
   
  /**
   * Ask for results.
   * @param beginRow
   * @param endRow
   */
    synchronized void requestResults(int beginRow, int endRow, ResultsReceiver<ResultsMessage> receiver) {
    if (this.resultsReceiver != null) {
      throw new IllegalStateException("Results already requested"); //$NON-NLS-1$\
    }
    this.resultsReceiver = receiver;
    this.begin = beginRow;
    this.end = endRow;
  }
   
  @Override
  protected boolean isDoneProcessing() {
    return isClosed;
  }

  @Override
  protected void resumeProcessing() {
    if (doneProducingBatches && !closeRequested && !isCanceled) {
      this.run(); // just run in the IO thread
    } else {
      dqpCore.addWork(this);
    }
  }
 
  @Override
  protected void interrupted(InterruptedException e) {
    try {
      this.requestCancel();
    } catch (TeiidComponentException e1) {
      throw new TeiidRuntimeException(e1);
    }
    super.interrupted(e);
  }
 
  @Override
  protected void process() {
        LogManager.logDetail(LogConstants.CTX_DQP, "Request Thread", requestID, "with state", state); //$NON-NLS-1$ //$NON-NLS-2$
        try {
            if (this.state == ProcessingState.NEW) {
                state = ProcessingState.PROCESSING;
            processNew();
                if (isCanceled) {
                  this.processingException = new TeiidProcessingException(QueryPlugin.Util.getString("QueryProcessor.request_cancelled", this.requestID)); //$NON-NLS-1$
                    state = ProcessingState.CLOSE;
                }
          }
         
            resume();
         
            if (this.state == ProcessingState.PROCESSING) {
              processMore();
              if (this.closeRequested) {
                this.state = ProcessingState.CLOSE;
              }
            }                               
        } catch (BlockedException e) {
            LogManager.logDetail(LogConstants.CTX_DQP, "Request Thread", requestID, "- processor blocked"); //$NON-NLS-1$ //$NON-NLS-2$
        } catch (QueryProcessor.ExpiredTimeSliceException e) {
            LogManager.logDetail(LogConstants.CTX_DQP, "Request Thread", requestID, "- time slice expired"); //$NON-NLS-1$ //$NON-NLS-2$
            this.moreWork();
        } catch (Throwable e) {
          LogManager.logDetail(LogConstants.CTX_DQP, e, "Request Thread", requestID, "- error occurred"); //$NON-NLS-1$ //$NON-NLS-2$
           
            if (!isCanceled()) {
              dqpCore.logMMCommand(this, Event.ERROR, null);
                //Case 5558: Differentiate between system level errors and
                //processing errors.  Only log system level errors as errors,
                //log the processing errors as warnings only
                if(e instanceof TeiidProcessingException) {                         
                  Throwable cause = e;
                  while (cause.getCause() != null && cause.getCause() != cause) {
                    cause = cause.getCause();
                  }
                  StackTraceElement[] elems = cause.getStackTrace();
                  Object elem = null;
                  if (elems.length > 0) {
                    elem = cause.getStackTrace()[0];
                  } else {
                    elem = cause.getMessage();
                  }
                    LogManager.logWarning(LogConstants.CTX_DQP, QueryPlugin.Util.getString("ProcessWorker.processing_error", e.getMessage(), requestID, e.getClass().getName(), elem)); //$NON-NLS-1$
                }else {
                    LogManager.logError(LogConstants.CTX_DQP, e, QueryPlugin.Util.getString("ProcessWorker.error", requestID)); //$NON-NLS-1$
                }                               
            }
           
            this.processingException = e;
            this.state = ProcessingState.CLOSE;
        } finally {
          if (this.state == ProcessingState.CLOSE && !isClosed) {
            attemptClose();
          } else if (isClosed) {
            /*
             * since there may be a client waiting notify them of a problem
             */
            if (this.processingException == null) {
              this.processingException = new IllegalStateException("Request is already closed"); //$NON-NLS-1$
            }
            sendError();
          }
          suspend();
        }
    }

  private void resume() throws XATransactionException {
    if (this.transactionState == TransactionState.ACTIVE && this.transactionContext.getTransaction() != null) {
      this.transactionService.resume(this.transactionContext);
    }
  }

  private void suspend() {
    try {
      this.transactionService.suspend(this.transactionContext);
    } catch (XATransactionException e) {
      LogManager.logDetail(LogConstants.CTX_DQP, e, "Error suspending active transaction"); //$NON-NLS-1$
    }
  }

  protected void processMore() throws BlockedException, TeiidException {
    if (!doneProducingBatches) {
      this.processor.getContext().setTimeSliceEnd(System.currentTimeMillis() + this.processorTimeslice);
      sendResultsIfNeeded(null);
      this.resultsBuffer = collector.collectTuples();
      if (!doneProducingBatches) {
        doneProducingBatches();
        addToCache();
      }
    }
    if (this.transactionState == TransactionState.ACTIVE) {
      /*
       * TEIID-14 if we are done producing batches, then proactively close transactional
       * executions even ones that were intentionally kept alive. this may
       * break the read of a lob from a transactional source under a transaction
       * if the source does not support holding the clob open after commit
       */
          for (DataTierTupleSource connectorRequest : this.connectorInfo.values()) {
            if (connectorRequest.isTransactional()) {
              connectorRequest.fullyCloseSource();
            }
            }
      this.transactionState = TransactionState.DONE;
      if (transactionContext.getTransactionType() == TransactionContext.Scope.REQUEST) {
        this.transactionService.commit(transactionContext);
      } else {
        suspend();
      }
    }
    sendResultsIfNeeded(null);
  }

  /**
   * Client close is currently implemented as asynch.
   * Any errors that occur will not make it to the client, instead we just log them here.
   */
  protected void attemptClose() {
    int rowcount = -1;
    if (this.resultsBuffer != null) {
      if (this.processor != null) {
        this.processor.closeProcessing();
     
        if (LogManager.isMessageToBeRecorded(LogConstants.CTX_DQP, MessageLevel.DETAIL)) {
              LogManager.logDetail(LogConstants.CTX_DQP, "Removing tuplesource for the request " + requestID); //$NON-NLS-1$
          }
        rowcount = resultsBuffer.getRowCount();
        if (this.cid == null || !this.doneProducingBatches) {
          resultsBuffer.remove();
        } else {
          try {
            this.resultsBuffer.persistLobs();
          } catch (TeiidComponentException e) {
            LogManager.logDetail(LogConstants.CTX_DQP, QueryPlugin.Util.getString("failed_to_cache")); //$NON-NLS-1$
          }
        }
       
        for (DataTierTupleSource connectorRequest : this.connectorInfo.values()) {
          connectorRequest.fullyCloseSource();
          }
      }

      this.resultsBuffer = null;
     
      for (LobWorkItem lobWorkItem : this.lobStreams.values()) {
        lobWorkItem.close();
      }
    }

    if (this.transactionState == TransactionState.ACTIVE) {
      this.transactionState = TransactionState.DONE;
            if (transactionContext.getTransactionType() == TransactionContext.Scope.REQUEST) {
        try {
              this.transactionService.rollback(transactionContext);
              } catch (XATransactionException e1) {
                  LogManager.logWarning(LogConstants.CTX_DQP, e1, QueryPlugin.Util.getString("ProcessWorker.failed_rollback")); //$NON-NLS-1$          
              }
      } else {
        suspend();
      }
    }
   
    isClosed = true;

    dqpCore.removeRequest(this);
     
    if (this.processingException != null) {
      sendError();     
    } else {
          dqpCore.logMMCommand(this, Event.END, rowcount);
    }
  }

  protected void processNew() throws TeiidProcessingException, TeiidComponentException {
    SessionAwareCache<CachedResults> rsCache = dqpCore.getRsCache();
       
    boolean cachable = false;
    CacheID cacheId = null;
    boolean canUseCached = (requestMsg.useResultSetCache() ||
        QueryParser.getQueryParser().parseCacheHint(requestMsg.getCommandString()) != null);
   
    if (rsCache != null) {
      if (!canUseCached) {
        LogManager.logDetail(LogConstants.CTX_DQP, requestID, "No cache directive"); //$NON-NLS-1$
      } else {
        ParseInfo pi = Request.createParseInfo(requestMsg);
        cacheId = new CacheID(this.dqpWorkContext, pi, requestMsg.getCommandString());
          cachable = cacheId.setParameters(requestMsg.getParameterValues());
        if (cachable) {
          CachedResults cr = rsCache.get(cacheId);
          if (cr != null) {
            this.resultsBuffer = cr.getResults();
            this.analysisRecord = cr.getAnalysisRecord();
            request.initMetadata();
            this.originalCommand = cr.getCommand(requestMsg.getCommandString(), request.metadata, pi);
            request.validateAccess(this.originalCommand);
            this.doneProducingBatches();
            return;
          }
        } else {
          LogManager.logDetail(LogConstants.CTX_DQP, requestID, "Parameters are not serializable - cache cannot be used for", cacheId); //$NON-NLS-1$
        }
      }
    }
    request.processRequest();
    originalCommand = request.userCommand;
        if (cachable && (requestMsg.useResultSetCache() || originalCommand.getCacheHint() != null) && rsCache != null && originalCommand.areResultsCachable()) {
          this.cid = cacheId;
          //turn on the collection of data objects used
          request.processor.getContext().setDataObjects(new HashSet<Object>(4));
        }
    processor = request.processor;
    collector = new BatchCollector(processor, processor.getBufferManager(), this.request.context, isForwardOnly()) {
      protected void flushBatchDirect(TupleBatch batch, boolean add) throws TeiidComponentException,TeiidProcessingException {
        resultsBuffer = getTupleBuffer();
        boolean added = false;
        if (cid != null) {
          super.flushBatchDirect(batch, add);
          added = true;
        }
        if (batch.getTerminationFlag()) {
          doneProducingBatches();
        }
        addToCache();
        add = sendResultsIfNeeded(batch);
        if (!added) {
          super.flushBatchDirect(batch, add);
          //restrict the buffer size for forward only results
          if (add && !processor.hasFinalBuffer()
              && !batch.getTerminationFlag()
              && this.getTupleBuffer().getManagedRowCount() >= 20 * this.getTupleBuffer().getBatchSize()) {
            //requestMore will trigger more processing
            throw BlockedException.INSTANCE;
          }
        }
      }
    };
    this.resultsBuffer = collector.getTupleBuffer();
    if (this.resultsBuffer == null) {
      //This is just a dummy result it will get replaced by collector source
        resultsBuffer = this.processor.getBufferManager().createTupleBuffer(this.originalCommand.getProjectedSymbols(), this.request.context.getConnectionID(), TupleSourceType.FINAL);
    }
    analysisRecord = request.analysisRecord;
    analysisRecord.setQueryPlan(processor.getProcessorPlan().getDescriptionProperties());
    transactionContext = request.transactionContext;
    if (this.transactionContext != null && this.transactionContext.getTransactionType() != Scope.NONE) {
      this.transactionState = TransactionState.ACTIVE;
    }
    if (requestMsg.isNoExec()) {
        doneProducingBatches();
            resultsBuffer.close();
            this.cid = null;
    }
      this.returnsUpdateCount = request.returnsUpdateCount;
    request = null;
  }
 
  private void addToCache() {
    if (!doneProducingBatches || cid == null) {
      return;
    }
      Determinism determinismLevel = processor.getContext().getDeterminismLevel();
      CachedResults cr = new CachedResults();
      cr.setCommand(originalCommand);
        cr.setAnalysisRecord(analysisRecord);
        cr.setResults(resultsBuffer, processor.getProcessorPlan());
        if (originalCommand.getCacheHint() != null) {
          LogManager.logDetail(LogConstants.CTX_DQP, requestID, "Using cache hint", originalCommand.getCacheHint()); //$NON-NLS-1$
      resultsBuffer.setPrefersMemory(originalCommand.getCacheHint().getPrefersMemory());
          if (originalCommand.getCacheHint().getDeterminism() != null) {
        determinismLevel = originalCommand.getCacheHint().getDeterminism();
        LogManager.logTrace(LogConstants.CTX_DQP, new Object[] { "Cache hint modified the query determinism from ",processor.getContext().getDeterminismLevel(), " to ", determinismLevel }); //$NON-NLS-1$ //$NON-NLS-2$
          }                   
        }               
       
        if (determinismLevel.compareTo(Determinism.SESSION_DETERMINISTIC) <= 0) {
      LogManager.logInfo(LogConstants.CTX_DQP, QueryPlugin.Util.getString("RequestWorkItem.cache_nondeterministic", originalCommand)); //$NON-NLS-1$
    }
        dqpCore.getRsCache().put(cid, determinismLevel, cr, originalCommand.getCacheHint() != null?originalCommand.getCacheHint().getTtl():null);
  }

  /**
   * Send results if they have been requested.  This should only be called from the processing thread.
   */
  protected boolean sendResultsIfNeeded(TupleBatch batch) throws TeiidComponentException {
    ResultsMessage response = null;
    ResultsReceiver<ResultsMessage> receiver = null;
    boolean result = true;
    synchronized (this) {
      if (this.resultsReceiver == null
          || (this.begin > (batch != null?batch.getEndRow():this.resultsBuffer.getRowCount()) && !doneProducingBatches)
          || (this.transactionState == TransactionState.ACTIVE)) {
        return result;
      }
   
      if (LogManager.isMessageToBeRecorded(LogConstants.CTX_DQP, MessageLevel.DETAIL)) {
        LogManager.logDetail(LogConstants.CTX_DQP, "[RequestWorkItem.sendResultsIfNeeded] requestID:", requestID, "resultsID:", this.resultsBuffer, "done:", doneProducingBatches );   //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      }
 
      //TODO: support fetching more than 1 batch
      boolean fromBuffer = false;
        if (batch == null || !(batch.containsRow(this.begin) || (batch.getTerminationFlag() && batch.getEndRow() <= this.begin))) {
          if (savedBatch != null && savedBatch.containsRow(this.begin)) {
            batch = savedBatch;
          } else {
            batch = resultsBuffer.getBatch(begin);
          }
          savedBatch = null;
          fromBuffer = true;
        }
        int count = this.end - this.begin + 1;
        if (batch.getRowCount() > count) {
          int beginRow = Math.min(this.begin, batch.getEndRow() - count + 1);
          int endRow = Math.min(beginRow + count - 1, batch.getEndRow());
          boolean last = false;
          if (endRow == batch.getEndRow()) {
            last = batch.getTerminationFlag();
          } else if (fromBuffer && isForwardOnly()) {
              savedBatch = batch;
          }
                List<List<?>> memoryRows = batch.getTuples();
                batch = new TupleBatch(beginRow, memoryRows.subList(beginRow - batch.getBeginRow(), endRow - batch.getBeginRow() + 1));
                batch.setTerminationFlag(last);
        } else if (!fromBuffer){
          result = !isForwardOnly();
        }
          int finalRowCount = this.resultsBuffer.isFinal()?this.resultsBuffer.getRowCount():(batch.getTerminationFlag()?batch.getEndRow():-1);
         
          response = createResultsMessage(batch.getAllTuples(), this.originalCommand.getProjectedSymbols());
          response.setFirstRow(batch.getBeginRow());
          response.setLastRow(batch.getEndRow());
          response.setUpdateResult(this.returnsUpdateCount);
          // set final row
          response.setFinalRow(finalRowCount);
 
          // send any warnings with the response object
          List<Throwable> responseWarnings = new ArrayList<Throwable>();
          if (this.processor != null) {
        List<Exception> currentWarnings = processor.getAndClearWarnings();
          if (currentWarnings != null) {
            responseWarnings.addAll(currentWarnings);
          }
          }
        synchronized (warnings) {
            responseWarnings.addAll(this.warnings);
            this.warnings.clear();
        }
          response.setWarnings(responseWarnings);
         
          // If it is stored procedure, set parameters
          if (originalCommand instanceof StoredProcedure) {
            StoredProcedure proc = (StoredProcedure)originalCommand;
            if (proc.returnParameters()) {
              response.setParameters(getParameterInfo(proc));
            }
          }
          /*
           * mark the results sent at this point.
           * communication exceptions will be treated as non-recoverable
           */
            receiver = this.resultsReceiver;
            this.resultsReceiver = null;   
    }
        receiver.receiveResults(response);
        return result;
  }
   
    public ResultsMessage createResultsMessage(List[] batch, List columnSymbols) {
        String[] columnNames = new String[columnSymbols.size()];
        String[] dataTypes = new String[columnSymbols.size()];

        for(int i=0; i<columnSymbols.size(); i++) {
            SingleElementSymbol symbol = (SingleElementSymbol) columnSymbols.get(i);
            columnNames[i] = SingleElementSymbol.getShortName(symbol.getOutputName());
            dataTypes[i] = DataTypeManager.getDataTypeName(symbol.getType());
        }
        ResultsMessage result = new ResultsMessage(requestMsg, batch, columnNames, dataTypes);
        setAnalysisRecords(result);
        return result;
    }
   
  private void setAnalysisRecords(ResultsMessage response) {
    if(analysisRecord != null) {
          if (requestMsg.getShowPlan() != ShowPlan.OFF) {
            if (processor != null) {
              analysisRecord.setQueryPlan(processor.getProcessorPlan().getDescriptionProperties());
            }
            response.setPlanDescription(analysisRecord.getQueryPlan());
              response.setAnnotations(analysisRecord.getAnnotations());
          }
            if (requestMsg.getShowPlan() == ShowPlan.DEBUG) {
              response.setDebugLog(analysisRecord.getDebugLog());
            }
        }
  }

    private void sendError() {
      ResultsReceiver<ResultsMessage> receiver = null;
      synchronized (this) {
        receiver = this.resultsReceiver;
        this.resultsReceiver = null;
        if (receiver == null) {
          LogManager.logDetail(LogConstants.CTX_DQP, processingException, "Unable to send error to client as results were already sent.", requestID); //$NON-NLS-1$
          return;
        }
      }
    LogManager.logDetail(LogConstants.CTX_DQP, processingException, "Sending error to client", requestID); //$NON-NLS-1$
        ResultsMessage response = new ResultsMessage(requestMsg);
        response.setException(processingException);
        setAnalysisRecords(response);
        receiver.receiveResults(response);
    }
   
    @Override
    protected boolean shouldPause() {
      //if we are waiting on results it's ok to pause
      return this.resultsReceiver != null;
    }

    private static List<ParameterInfo> getParameterInfo(StoredProcedure procedure) {
        List<ParameterInfo> paramInfos = new ArrayList<ParameterInfo>();
       
        for (SPParameter param : procedure.getParameters()) {
            ParameterInfo info = new ParameterInfo(param.getParameterType(), param.getResultSetColumns().size());
            paramInfos.add(info);
        }
       
        return paramInfos;
    }
   
    public void processLobChunkRequest(String id, int streamRequestId, ResultsReceiver<LobChunk> chunckReceiver) {
      LobWorkItem workItem = null;
      synchronized (lobStreams) {
            workItem = this.lobStreams.get(new Integer(streamRequestId));
            if (workItem == null) {
              workItem = new LobWorkItem(this, dqpCore, id, streamRequestId);
              lobStreams.put(new Integer(streamRequestId), workItem);
            }
    }
      workItem.setResultsReceiver(chunckReceiver);
      if (this.dqpWorkContext.useCallingThread()) {
        workItem.run();
      } else {
        dqpCore.addWork(workItem);
      }
    }
   
    public void removeLobStream(int streamRequestId) {
        this.lobStreams.remove(new Integer(streamRequestId));
    }
   
    public boolean requestCancel() throws TeiidComponentException {
      synchronized (this) {
          if (this.isCanceled || this.closeRequested) {
            return false;
          }
          this.isCanceled = true;
    }
      if (this.processor != null) {
        this.processor.requestCanceled();
      }
     
        // Cancel Connector atomic requests
        try {
          for (DataTierTupleSource connectorRequest : this.connectorInfo.values()) {
                connectorRequest.cancelRequest();
            }
        } finally {
          try {
              if (transactionService != null) {
                  try {
                      transactionService.cancelTransactions(requestID.getConnectionID(), true);
                  } catch (XATransactionException err) {
                      throw new TeiidComponentException(err);
                  }
              }
          } finally {
            this.moreWork();
          }
        }
        return true;
    }
   
    public boolean requestAtomicRequestCancel(AtomicRequestID ari) throws TeiidComponentException {
      // in the case that this does not support partial results; cancel
        // the original processor request.
        if(!requestMsg.supportsPartialResults()) {
          return requestCancel();
        }
       
        DataTierTupleSource connectorRequest = this.connectorInfo.get(ari);
        if (connectorRequest != null) {
          connectorRequest.cancelRequest();
          return true;
        }
       
    LogManager.logDetail(LogConstants.CTX_DQP, "Connector request not found. AtomicRequestID=", ari); //$NON-NLS-1$
        return false;
    }
   
    public void requestClose() throws TeiidComponentException {
      synchronized (this) {
          if (this.state == ProcessingState.CLOSE || this.closeRequested) {
            if (LogManager.isMessageToBeRecorded(LogConstants.CTX_DQP, MessageLevel.DETAIL)) {
              LogManager.logDetail(LogConstants.CTX_DQP, "Request already closing" + requestID); //$NON-NLS-1$
            }
            return;
          }
    }
      this.closeRequested = true;
      if (!this.doneProducingBatches) {
        this.requestCancel(); //pending work should be canceled for fastest clean up
      }
      this.moreWork();
    }
   
    public void requestMore(int batchFirst, int batchLast, ResultsReceiver<ResultsMessage> receiver) {
      this.requestResults(batchFirst, batchLast, receiver);
      this.moreWork();
    }
   
    public void closeAtomicRequest(AtomicRequestID atomicRequestId) {
        connectorInfo.remove(atomicRequestId);
        LogManager.logTrace(LogConstants.CTX_DQP, new Object[] {"closed atomic-request:", atomicRequestId})//$NON-NLS-1$
    }
   
  public void addConnectorRequest(AtomicRequestID atomicRequestId, DataTierTupleSource connInfo) {
    connectorInfo.put(atomicRequestId, connInfo);
  }
   
    /**
   * <p>This method add information to the warning on the work item for the given
   * <code>RequestID</code>. This method is called from <code>DataTierManager</code></p>
   */
    public void addSourceFailureDetails(SourceWarning details) {
      synchronized (warnings) {
      this.warnings.add(details);
      }
  }
       
  boolean isCanceled() {
    return isCanceled;
  }
 
  Command getOriginalCommand() throws TeiidProcessingException {
    if (this.originalCommand == null) {
      if (this.processingException != null) {
        throw new TeiidProcessingException(this.processingException);
      }
      throw new IllegalStateException("Original command is not available"); //$NON-NLS-1$
    }
    return this.originalCommand;
  }
 
  void setOriginalCommand(Command originalCommand) {
    this.originalCommand = originalCommand;
  }

  TransactionContext getTransactionContext() {
    return transactionContext;
  }
 
 
  Collection<DataTierTupleSource> getConnectorRequests() {
    return new LinkedList<DataTierTupleSource>(this.connectorInfo.values());
  }
 
  DataTierTupleSource getConnectorRequest(AtomicRequestID id) {
    return this.connectorInfo.get(id);
  }
 
  public List<TeiidException> getWarnings() {
    return warnings;
  }

  @Override
  public String toString() {
    return this.requestID.toString();
  }

  public DQPWorkContext getDqpWorkContext() {
    return dqpWorkContext;
  }
 
  public long getProcessingTimestamp() {
    return processingTimestamp;
  }
 
  @Override
  public void release() {
    try {
      requestCancel();
    } catch (TeiidComponentException e) {
      LogManager.logWarning(LogConstants.CTX_DQP, e, "Failed to cancel " + requestID); //$NON-NLS-1$
    }
  }

  private void doneProducingBatches() {
    this.doneProducingBatches = true;
    dqpCore.finishProcessing(this);
  }
 
  @Override
  public int getPriority() {
    return (closeRequested || isCanceled) ? 0 : 1000;
  }
 
  @Override
  public long getCreationTime() {
    return processingTimestamp;
 
 
  <T> FutureWork<T> addHighPriorityWork(Callable<T> callable) {
    FutureWork<T> work = new FutureWork<T>(callable, PrioritizedRunnable.NO_WAIT_PRIORITY);
    dqpCore.addWork(work);
    return work;
  }
 
    <T> FutureWork<T> addWork(Callable<T> callable, CompletionListener<T> listener, int priority) {
      FutureWork<T> work = new FutureWork<T>(callable, priority);
      WorkWrapper<T> wl = new WorkWrapper<T>(work);
      work.addCompletionListener(wl);
      work.addCompletionListener(listener);
      synchronized (queue) {
          if (totalThreads < dqpCore.getUserRequestSourceConcurrency()) {
            dqpCore.addWork(work);
            totalThreads++;
            wl.submitted = true;
          } else {
            queue.add(wl);
            LogManager.logDetail(LogConstants.CTX_DQP, this.requestID, " reached max source concurrency of ", dqpCore.getUserRequestSourceConcurrency()); //$NON-NLS-1$
          }
      }
      return work;
    }
   
    void scheduleWork(Runnable r, int priority, long delay) {
      dqpCore.scheduleWork(r, priority, delay);
    }

}
TOP

Related Classes of org.teiid.dqp.internal.process.RequestWorkItem$WorkWrapper

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.