示例#1
0
// ExSampleTcb constructor
//
// 1. Allocate buffer pool.
// 2. Allocate parent queues and initialize private state.
// 3. Fixup expressions.
//
ExSampleTcb::ExSampleTcb
(const ExSampleTdb &  myTdb, 
 const ex_tcb &    child_tcb,
 ex_globals * glob
 ) : 
  ex_tcb(myTdb, 1, glob)
{
  Space * space = (glob ? glob->getSpace() : 0);
  CollHeap * heap = (glob ? glob->getDefaultHeap() : 0);
  
  childTcb_ = &child_tcb;

   // get the queue that child use to communicate with me
  qchild_  = child_tcb.getParentQueue(); 

  // Allocate the queue to communicate with parent
  qparent_.down = new(space) ex_queue(ex_queue::DOWN_QUEUE,
							myTdb.queueSizeDown_,
				     myTdb.criDescDown_,
				     space);
  
  // Allocate the private state in each entry of the down queue
  ExSamplePrivateState *p 
    = new(space) ExSamplePrivateState(this);
  qparent_.down->allocatePstate(p, this);
  delete p;


  qparent_.up = new(space) ex_queue(ex_queue::UP_QUEUE,
				    myTdb.queueSizeUp_,
				    myTdb.criDescUp_,
				    space);

  // Intialized processedInputs_ to the next request to process
  processedInputs_ = qparent_.down->getTailIndex();

  // Fixup the sample expression
  //
  if (initExpr())
    initExpr()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);

  if (balanceExpr())
    balanceExpr()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);

  if (postPred())
    postPred()->fixup(0, getExpressionMode(), this, space, heap, FALSE, glob);
}
// work - doit...
//
//
short ExSequenceTcb::work()
{
  // If there are no parent requests on the queue, then there cannot
  // be anything to do here.
  //
  if (qparent_.down->isEmpty())
    return WORK_OK;

  ex_queue_entry * pentry_down;
  ExSequencePrivateState * pstate;
  ex_queue::down_request request;

  // Take any new parent requests and pass them on to the child as long
  // as the child's queue is not full. processedInputs_ maintains the 
  // Queue index of the last request that was passed on.
  // 
  for(queue_index tail = qparent_.down->getTailIndex(); 
      (processedInputs_ != tail) && (!qchild_.down->isFull());
      processedInputs_++ )
    {
      pentry_down = qparent_.down->getQueueEntry(processedInputs_);
      pstate = (ExSequencePrivateState*) pentry_down->pstate;
      request = pentry_down->downState.request;

      // If the request has already been cancelled don't pass it to the
      // child. Instead, just mark the request as done. This will trigger
      // a EOD reply when this request gets worked on.
      //
      if (request == ex_queue::GET_NOMORE)
        {
          // LCOV_EXCL_START
          pstate->step_ = ExSeq_DONE;
          // LCOV_EXCL_STOP
        }
      else
        {
          pstate->step_ = ExSeq_WORKING_READ;

          // Pass the request to the child
          //
          ex_queue_entry * centry = qchild_.down->getTailEntry();
          centry->downState.request = ex_queue::GET_ALL;
          centry->downState.requestValue = 11;
          centry->downState.parentIndex = processedInputs_;
          centry->passAtp(pentry_down);
          qchild_.down->insert();
        }
    } // end for processedInputs_

  pentry_down = qparent_.down->getHeadEntry();
  pstate = (ExSequencePrivateState*) pentry_down->pstate;
  request = pentry_down->downState.request;

  // Take any child replies and process them. Return the processed
  // rows as long the parent queue has room.
  //
  while (1)
    {
      // If we have satisfied the parent request (or it was cancelled),
      // then stop processing rows, cancel any outstanding child
      // requests, and set this request to the CANCELLED state.
      //
      if ((pstate->step_ == ExSeq_WORKING_READ) ||
          (pstate->step_ == ExSeq_WORKING_RETURN))
        {
          if ((request == ex_queue::GET_NOMORE) ||
              ((request == ex_queue::GET_N) &&
               (pentry_down->downState.requestValue 
                <= (Lng32)pstate->matchCount_)))
            {
              qchild_.down->cancelRequestWithParentIndex
                (qparent_.down->getHeadIndex());
              pstate->step_ = ExSeq_CANCELLED;
            }
        }

      switch (pstate->step_)
        {
          // ExSeq_CANCELLED
          //
          // Transition to this state from ...
          // 1. ExSeq_Error - After the error has been processed.
          // 2. ExSeq_Working - If enough rows have been returned.
          // 3. ExSeq_Working - If the request was cancelled.
          //
          // Remain in this state until ..
          // 1. All rows from the child including EOD are consumed
          //
          // Transition from this state to ...
          // 1. ExSeq_DONE - In all cases.
          //
        case ExSeq_CANCELLED:
          {
            // There are no extra rows to process from the child yet,
            // so try again later.
            //
            if (qchild_.up->isEmpty())
              {
                return WORK_OK;
              }

            ex_queue_entry * centry = qchild_.up->getHeadEntry();
            ex_queue::up_status child_status = centry->upState.status;

            // If this is the EOD, transition to the ExSeq_DONE state.
            //
            if (child_status == ex_queue::Q_NO_DATA)
                  pstate->step_ = ExSeq_DONE;

            // Discard the child row.
            qchild_.up->removeHead();	    
            break;
          }

        // ExSeq_ERROR
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - a child reply with the type SQLERROR.
        // 2. ExSeq_WORKING_RETURN
        // 3. ExSeq_OVERFLOW_READ
        // 4. ExSeq_OVERFLOW_WRITE
        // Remain in this state until ..
        // 1. The error row has been returned to the parent.
        //
        // Transition from this state to ...
        // 1. ExSeq_CANCELLED - In all cases.
        //
        case ExSeq_ERROR:
          {
            // If there is no room in the parent queue for the reply,
            // try again later.
            //
            if (qparent_.up->isFull())
              // LCOV_EXCL_START
              return WORK_OK;
              // LCOV_EXCL_STOP

            ex_queue_entry *pentry_up = qparent_.up->getTailEntry();

            // Cancel the child request - there must be a child request in
            // progress to get to the ExSeq_ERROR state.
            //
            qchild_.down->cancelRequestWithParentIndex
              (qparent_.down->getHeadIndex());

            // Construct and return the error row.
            //
            if (workAtp_->getDiagsArea()) {
              ComDiagsArea * da = workAtp_->getDiagsArea();
              pentry_up->setDiagsArea(da);
              da->incrRefCount();
              workAtp_->setDiagsArea(0);
            }
            pentry_up->upState.status = ex_queue::Q_SQLERROR;
            pentry_up->upState.parentIndex 
              = pentry_down->downState.parentIndex;
            pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            qparent_.up->insert();

            // Transition to the ExSeq_CANCELLED state.
            //
            pstate->step_ = ExSeq_CANCELLED;
            break;
          }

        // ExSeq_WORKING_READ
        //
        // Transition to this state from ...
        // 1. ExSeq_EMPTY - If a request is started.
        // 2. ExSeq_WORKING_RETURN - 
        // 3. ExSeq_OVERFLOW_WRITE - 
        // Remain in this state until ...
        // 1. All child replies including EOD have been processed.
        // 2. A SQLERROR row is received.
        // 3. Enough rows have been returned.
        // 4. The request is cancelled.
        // 5. End of partition is reached
        // Transition from this state to ...
	// 2. ExSeq_ERROR - If an SQLERROR rows is received.
        // 3. ExSeq_CANCELLED - If the request is cancelled.
        // 4. ExSeq_WORKING_RETURN
        // 5. ExSeq_OVERFLOW_WRITE - 
        case ExSeq_WORKING_READ:
          {
            if(!isUnboundedFollowing() && isHistoryFull()) {
              pstate->step_ = ExSeq_WORKING_RETURN;
              break;
            }
            // If there are no replies, try again later.
            //
            if (qchild_.up->isEmpty())
              return WORK_OK;

            ex_queue_entry * centry = qchild_.up->getHeadEntry();
            switch (centry->upState.status)
            {
              // A data row from the child.
              //
            case ex_queue::Q_OK_MMORE:
              {
                tupp_descriptor histTupp;
                workAtp_->copyAtp(pentry_down->getAtp());
                workAtp_->getTupp(myTdb().tuppIndex_) = &histTupp;

                if ( checkPartitionChangeExpr() &&
                       currentHistRowPtr_)
                {
                  workAtp_->getTupp
                    (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_);

                  // Check whether the partition changed
                  ex_expr::exp_return_type retCode = checkPartitionChangeExpr()->eval(workAtp_, centry->getAtp());
                  
                  if (retCode == ex_expr::EXPR_ERROR)
                  {
                    // LCOV_EXCL_START
                    updateDiagsArea(centry);
                    pstate->step_ = ExSeq_ERROR;
                    break;
                    // LCOV_EXCL_STOP
                  }
                  if ( retCode == ex_expr::EXPR_FALSE)
                  {
                    setPartitionEnd(TRUE);
                    pstate->step_ = ExSeq_END_OF_PARTITION;
                    break;
                  }
                }


                if (isUnboundedFollowing() )
                {
                  if (OLAPBuffersFlushed_)
                  {
                    OLAPBuffersFlushed_ = FALSE;// current row is the first one in first buffer already
                  }
                  else
                  {
                    NABoolean noMemory = 
		      advanceHistoryRow( TRUE /* checkMemoryPressure */);
                    if (noMemory)
                    {
                      pstate->step_ = ExSeq_OVERFLOW_WRITE;
                      cluster_->nextBufferToFlush_ = firstOLAPBuffer_;
		      cluster_->afterLastBufferToFlush_ = NULL;//flush them all

		      // If it is the first overflow, for this partition
		      if ( ! memoryPressureDetected_ ) {
			memoryPressureDetected_ = TRUE;
			
		      } // memory pressure detected

                      break;
                    }
                  }
                }
                else
                {
                  advanceHistoryRow();
                }
 
                workAtp_->getTupp
                  (myTdb().tuppIndex_).setDataPointer(currentHistRowPtr_);

                ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;

                // Apply the read phase sequence function expression to compute 
                // the values of the sequence functions.
                if (sequenceExpr())
                {
                  retCode = sequenceExpr()->eval(workAtp_, centry->getAtp());
                  if (retCode == ex_expr::EXPR_ERROR)
                  {
                    updateDiagsArea(centry);
                    pstate->step_ = ExSeq_ERROR;
                    break;
                  }
                }

                // merge the child's diags area into the work atp
                updateDiagsArea(centry);

                qchild_.up->removeHead();

                break;
              }

              // The EOD from the child. Transition to ExSeq_DONE.
              //
            case ex_queue::Q_NO_DATA:
              {
                setPartitionEnd(TRUE);
                if (isHistoryEmpty())
                {
                  pstate->step_ = ExSeq_DONE;
                  qchild_.up->removeHead();
                }
                else
                {
                  pstate->step_ = ExSeq_END_OF_PARTITION;
                }
              }
              break;

              // An SQLERROR from the child. Transition to ExSeq_ERROR.
              //
            case ex_queue::Q_SQLERROR:
              updateDiagsArea(centry);
              pstate->step_ = ExSeq_ERROR;
              break;
            }
          }
          break;
        // ExSeq_WORKING_RETURN
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // 2. ExSeq_OVERFLOW_READ - 
        // 3. ExSeq_END_OF_PARTITION - 
        // Remain in this state until ...
        // 1. All rows are returned.
        // 2. A SQLERROR row is received.
        // 3. Enough rows have been returned.
        //
        // Transition from this state to ...
        // 1. ExSeq_DONE - If all the child rows including EOD have 
        //    been processed.
        // 2. ExSeq_ERROR - If an SQLERROR rows is received.
        // 3. ExSeq_CANCELLED - If enough rows have been returned.
        // 4. ExSeq_CANCELLED - If the request is cancelled.
        // 5. ExSeq_WORKING_RETURN        
        // 6. ExSeq_DONE   
	// 7. ExSeq_OVERFLOW_READ     
        case ExSeq_WORKING_RETURN:
          {
            // If there is not room in the parent Queue for the reply,
            // try again later.
            //
            if (qparent_.up->isFull())
              return WORK_OK;

            if(isHistoryEmpty()) 
            {
              ex_queue_entry * centry = NULL;
              if(!qchild_.up->isEmpty()) 
              {
                centry = qchild_.up->getHeadEntry();
              }
              if(centry && (centry->upState.status == ex_queue::Q_NO_DATA)) 
              {
                pstate->step_ = ExSeq_DONE;
                qchild_.up->removeHead();
              } 
              else 
              {
                pstate->step_ = ExSeq_WORKING_READ;

                if (getPartitionEnd())
                {
                  initializeHistory();
                }
              }
              break;
            }

            if(!canReturnRows() && 
               !getPartitionEnd() &&
               !isUnboundedFollowing() &&
               !isOverflowStarted()) // redundant? because not unbounded ... 
            {
              pstate->step_ = ExSeq_WORKING_READ;
              break;
            }
            
            ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
                
            pentry_up->copyAtp(pentry_down);
            // Try to allocate a tupp.
            //
            if (pool_->get_free_tuple(pentry_up->getTupp(myTdb().tuppIndex_),
                                      recLen()))
              // LCOV_EXCL_START
              return WORK_POOL_BLOCKED;
              // LCOV_EXCL_STOP 

            char *tuppData = pentry_up->getTupp
              (myTdb().tuppIndex_).getDataPointer();

            advanceReturnHistoryRow();

            char *histData = currentRetHistRowPtr_; 
            pentry_up->getTupp
              (myTdb().tuppIndex_).setDataPointer(histData);

            ex_expr::exp_return_type retCode = ex_expr::EXPR_OK;
            // Apply the return phase expression
            if(returnExpr())
            {
              retCode = returnExpr()->eval(pentry_up->getAtp(),workAtp_);
              if (retCode == ex_expr::EXPR_ERROR)
              {
                // LCOV_EXCL_START
                pstate->step_ = ExSeq_ERROR;
                break;
                // LCOV_EXCL_STOP
              }
            }

            retCode = ex_expr::EXPR_OK;
            //Apply post predicate expression  
            if (postPred()) 
            {
              retCode = postPred()->eval(pentry_up->getAtp(),pentry_up->getAtp());
              if (retCode == ex_expr::EXPR_ERROR)
              {
                // LCOV_EXCL_START
                pstate->step_ = ExSeq_ERROR;
                break;
                // LCOV_EXCL_STOP
              }
            }

//pentry_up->getAtp()->display("return eval result", myTdb().getCriDescUp());

            //
            // Case-10-030724-7963: we are done pointing the tupp at the
            // history buffer, so point it back to the SQL buffer.
            //
            pentry_up->getTupp
              (myTdb().tuppIndex_).setDataPointer(tuppData);

            switch(retCode) {
            case ex_expr::EXPR_OK:
            case ex_expr::EXPR_TRUE:
            case ex_expr::EXPR_NULL:

              // Copy the row that was computed in the history buffer,
              // to the space previously allocated in the SQL buffer.

              str_cpy_all(tuppData, histData, recLen());

              // Return the processed row.
              //

              // Finalize the queue entry, then insert it
              //
              pentry_up->upState.status = ex_queue::Q_OK_MMORE;
              pentry_up->upState.parentIndex 
                = pentry_down->downState.parentIndex;
              pentry_up->upState.downIndex =
                qparent_.down->getHeadIndex();
              pstate->matchCount_++;
              pentry_up->upState.setMatchNo(pstate->matchCount_);
              qparent_.up->insert();
              break;

              // If the selection predicate returns FALSE,
              // do not return the child row.
              //
            case ex_expr::EXPR_FALSE:
              break;
                    
              // If the selection predicate returns an ERROR,
              // go to the error processing state.
              //
            case ex_expr::EXPR_ERROR:
              // LCOV_EXCL_START
              pstate->step_ = ExSeq_ERROR;
              // LCOV_EXCL_STOP
              break;
            }

            // MV --
            // Now, if there are no errors so far, evaluate the
            // cancel expression
            if ((pstate->step_ != ExSeq_ERROR) && cancelExpr()) 
              {

                // Temporarily point the tupp to the tail of the
                // history buffer for evaluating the
                // expressions.
                //
                pentry_up->getTupp
                  (myTdb().tuppIndex_).setDataPointer(histData);

                retCode = 
                  cancelExpr()->eval(pentry_up->getAtp(),pentry_up->getAtp());
        
                // We are done pointing the tupp at the history
                // buffer, so point it back to the SQL buffer.
                //
                pentry_up->getTupp
                  (myTdb().tuppIndex_).setDataPointer(tuppData);

                if (retCode == ex_expr::EXPR_TRUE)
                  {
                    qchild_.down->cancelRequestWithParentIndex
                      (qparent_.down->getHeadIndex());
                    pstate->step_ = ExSeq_CANCELLED;
                  }
              }

            updateHistRowsToReturn();
            if ( isOverflowStarted() )
            {
              numberOfRowsReturnedBeforeReadOF_ ++;
              if (numberOfRowsReturnedBeforeReadOF_ == maxNumberOfRowsReturnedBeforeReadOF_)
              {
                firstOLAPBufferFromOF_ = currentRetOLAPBuffer_->getNext();
                if (firstOLAPBufferFromOF_ == NULL)
                {
                  firstOLAPBufferFromOF_ = firstOLAPBuffer_;
                }
                for( Int32 i = 0; i < numberOfWinOLAPBuffers_; i++)
                {
                  firstOLAPBufferFromOF_ = firstOLAPBufferFromOF_->getNext();
                  if (firstOLAPBufferFromOF_ == NULL)
                  {
                    firstOLAPBufferFromOF_ = firstOLAPBuffer_;
                  }
                }
                numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_ - numberOfWinOLAPBuffers_;

		cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_;
		HashBuffer * afterLast = firstOLAPBufferFromOF_; 
		// last buffer to read into is the current buffer - maybe ?
		for ( Lng32 bufcount = numberOfOLAPBuffersFromOF_ ;
		      bufcount ;
		      bufcount-- ) {
		  afterLast = afterLast->getNext() ;
		  // Don't cycle back if bufcount == 1 because the logic in
		  // Cluster::read relies on the NULL ptr to stop reading
		  if ( bufcount > 1 && ! afterLast ) 
		    afterLast = firstOLAPBuffer_; // cycle back
		}
		// The last buffer to read to is always the current buffer
		// ex_assert ( afterLast == currentRetOLAPBuffer_->getNext(),
		//	    "Miscalculated the last buffer to read into"); 

		cluster_->afterLastBufferToRead_ = afterLast;

                pstate->step_ = ExSeq_OVERFLOW_READ;
              }
            }
          }
          break;

        // ExSeq_END_OF_PARTITION
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // Transition from this state to ...
        // 1. ExSeq_OVERFLOW_WRITE
        // 2. ExSeq_WORKING_RETURN        

        case ExSeq_END_OF_PARTITION:
        {
          setPartitionEnd(TRUE);
          if (lastRow_  && isUnboundedFollowing())
          {
            ex_assert(currentHistRowPtr_ != NULL, "ExSequenceTcb::work() - currentHistRowPtr_ is a NULL pointer");
            str_cpy_all(lastRow_, currentHistRowPtr_, recLen()); 
          }

          if ( isOverflowStarted() ) // we are overflowing
          {
            cluster_->nextBufferToFlush_ = firstOLAPBuffer_;
	    // do not flush beyond the current buffer
	    cluster_->afterLastBufferToFlush_ = currentOLAPBuffer_->getNext();
            pstate->step_ = ExSeq_OVERFLOW_WRITE;
          }
          else
          {
            pstate->step_ = ExSeq_WORKING_RETURN;
          }
        }
        break;

        // ExSeq_OVERFLOW_WRITE
        //
        // Transition to this state from ...
        // 1. ExSeq_WORKING_READ - 
        // 2. ExSeq_END_OF_PARTITION - 
        // Remain in this state until ...
        // 1. OLAPbuffers are written to oveflow space.
        // 2. An error occurs
        //
        // Transition from this state to ...
        // 1. ExSeq_OVERFLOW_READ
        // 2. ExSeq_ERROR - If an error occurs
        case ExSeq_OVERFLOW_WRITE:
        {
          if (!overflowEnabled_)
          {
           // LCOV_EXCL_START
           // used for debugging when CmpCommon::getDefault(EXE_BMO_DISABLE_OVERFLOW)is set to off ;
            updateDiagsArea(EXE_OLAP_OVERFLOW_NOT_SUPPORTED);
            pstate->step_ = ExSeq_ERROR;
            break;
            // LCOV_EXCL_STOP
          }
          ex_assert(isUnboundedFollowing(),"");
 
	  if ( ! cluster_->flush(&rc_) ) {  // flush the buffers
            // LCOV_EXCL_START
            // if no errors this code path is not visited
	    if ( rc_ ) 
            { // some error
              updateDiagsArea( rc_);
              pstate->step_ = ExSeq_ERROR;
	      break;
	    }
            // LCOV_EXCL_STOP
	    // not all the buffers are completely flushed. An I/O is pending
            // LCOV_EXCL_START
            // maybe we cane remove in the future
	    return WORK_OK; 
            // LCOV_EXCL_STOP
	  }

	  // At this point -- all the buffers were completely flushed

	  OLAPBuffersFlushed_ = TRUE;

          if (getPartitionEnd())
          {
            firstOLAPBufferFromOF_ = firstOLAPBuffer_;
            numberOfOLAPBuffersFromOF_ = numberOfOLAPBuffers_;

	    cluster_->nextBufferToRead_ = firstOLAPBufferFromOF_;
	    // First time we read and fill all the buffers
	    cluster_->afterLastBufferToRead_ = NULL; 

            pstate->step_ = ExSeq_OVERFLOW_READ;  
          }
          else
          {
            pstate->step_ = ExSeq_WORKING_READ;
          }
        }
        break;
        // ExSeq_OVERFLOW_READ
        //
        // Transition to this state from ...
        // 1. ExSeq_OVERFLOW_WRITE  
        // 2. ExSeq_WORKING_RETURN 
        // Remain in this state until ...
        // 1. OLAPbuffers are read from oveflow space.
        // 2. An error occurs
        //
        // Transition from this state to ...
        // 1. ExSeq_WORKING_RETURN
        // 2. ExSeq_ERROR - If an error occurs
         case ExSeq_OVERFLOW_READ:
        {

            assert(firstOLAPBufferFromOF_ &&
                    isUnboundedFollowing() );

	    if ( ! cluster_->read(&rc_) ) {
              // LCOV_EXCL_START
	      if ( rc_ ) { // some error
                updateDiagsArea( rc_);
		pstate->step_ = ExSeq_ERROR;
		break;
	      }
              // LCOV_EXCL_STOP
	      // not all the buffers are completely read. An I/O is pending
              // LCOV_EXCL_START
	      return WORK_OK;
              // LCOV_EXCL_STOP 
	    }

            numberOfRowsReturnedBeforeReadOF_ = 0;
            pstate->step_ = ExSeq_WORKING_RETURN;
	}
	break;

        // ExSeq_DONE
        //
        // Transition to the state from ...
        // 1. ExSeq_WORKING_RETURN - if all child rows have been processed.
        // 2. ExSeq_CANCELLED - if all child rows have been consumed.
        // 3. ExSeq_EMPTY - if the request was DOA.
        //
        // Remain in this state until ...
        // 1. The EOD is returned to the parent.
        //
        // Transition from this state to ...
        // 1. ExSeq_EMPTY - In all cases.
        //
        case ExSeq_DONE:
          {
            // If there is not any room in the parent's queue, 
            // try again later.
            //
            if (qparent_.up->isFull())
              // LCOV_EXCL_START
              return WORK_OK;
              // LCOV_EXCL_STOP
            
            ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
            pentry_up->upState.status = ex_queue::Q_NO_DATA;
            pentry_up->upState.parentIndex 
              = pentry_down->downState.parentIndex;
            pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            
            qparent_.down->removeHead();
            qparent_.up->insert();

            // Re-initialize pstate
            //
            pstate->step_ = ExSeq_EMPTY;
            pstate->matchCount_ = 0;
            workAtp_->release();

            // Initialize the history buffer in preparation for the
            // next request.
            //
            initializeHistory();

            // If there are no more requests, simply return.
            //
            if (qparent_.down->isEmpty())
              return WORK_OK;
           
            // LCOV_EXCL_START
            // If we haven't given to our child the new head
            // index return and ask to be called again.
            //
            if (qparent_.down->getHeadIndex() == processedInputs_)
              return WORK_CALL_AGAIN;

            // Position at the new head of the request queue.
            //
            pentry_down = qparent_.down->getHeadEntry();
            pstate = (ExSequencePrivateState*) pentry_down->pstate;
            request = pentry_down->downState.request; 
            // LCOV_EXCL_STOP
          }
        break;
        } // switch pstate->step_
    } // while
}
// ExSequenceTcb constructor
//
// 1. Allocate buffer pool.
// 2. Allocate parent queues and initialize private state.
// 3. Fixup expressions.
//
ExSequenceTcb::ExSequenceTcb (const ExSequenceTdb &  myTdb, 
                              const ex_tcb &    child_tcb,
                              ex_globals * glob) : 
  ex_tcb(myTdb, 1, glob),
  lastRow_(NULL),
  clusterDb_(NULL),
  cluster_(NULL),
  ioEventHandler_(NULL),
  OLAPBuffersFlushed_(FALSE),
  firstOLAPBuffer_(NULL),
  lastOLAPBuffer_(NULL),
  rc_(EXE_OK),
  olapBufferSize_(0),
  maxNumberOfOLAPBuffers_(0),
  numberOfOLAPBuffers_(0),
  minNumberOfOLAPBuffers_(0),
  memoryPressureDetected_(FALSE)
{

  Space * space = (glob ? glob->getSpace() : 0);
  CollHeap * heap = (glob ? glob->getDefaultHeap() : 0);
  heap_ = heap;

  childTcb_ = &child_tcb;

  // Allocate the buffer pool
#pragma nowarn(1506)   // warning elimination 
  pool_ = new(space) sql_buffer_pool(myTdb.numBuffers_,
    myTdb.bufferSize_,
    space);

  allocRowLength_ = ROUND8(myTdb.recLen_);

#pragma warn(1506)  // warning elimination 

  // Initialize the machinery for maintaining the row history for
  // computing sequence functions.
  //

  maxNumberHistoryRows_ = myTdb.maxHistoryRows_;
  minFollowing_ = myTdb.minFollowing_;
  unboundedFollowing_ = myTdb.isUnboundedFollowing();
  maxNumberOfOLAPBuffers_ = myTdb.maxNumberOfOLAPBuffers_;//testing
  olapBufferSize_ = myTdb.OLAPBufferSize_ ;
  maxRowsInOLAPBuffer_ = myTdb.maxRowsInOLAPBuffer_;
  minNumberOfOLAPBuffers_ = myTdb.minNumberOfOLAPBuffers_;
  numberOfWinOLAPBuffers_ = myTdb.numberOfWinOLAPBuffers_;
  overflowEnabled_ = ! myTdb.isNoOverflow();

  ex_assert( maxNumberOfOLAPBuffers_ >= minNumberOfOLAPBuffers_ ,
	     "maxNumberOfOLAPBuffers is too small");

  // Initialize history parameters
  // For unbounded following -- also create/initialize clusterDb, cluster
  initializeHistory();

  // get the queue that child use to communicate with me
  qchild_  = child_tcb.getParentQueue(); 

  // Allocate the queue to communicate with parent
  qparent_.down = new(space) ex_queue(ex_queue::DOWN_QUEUE,
    myTdb.initialQueueSizeDown_,
    myTdb.criDescDown_,
    space);

  // Allocate the private state in each entry of the down queue
  ExSequencePrivateState *p 
    = new(space) ExSequencePrivateState(this);
  qparent_.down->allocatePstate(p, this);
  delete p;

  qparent_.up = new(space) ex_queue(ex_queue::UP_QUEUE,
    myTdb.initialQueueSizeUp_,
    myTdb.criDescUp_,
    space);

  // Intialized processedInputs_ to the next request to process
  processedInputs_ = qparent_.down->getTailIndex();


  workAtp_ = allocateAtp(myTdb.criDescUp_, space);

  // Fixup the sequence function expression. This requires the standard
  // expression fixup plus initializing the GetRow method for the sequence
  // clauses.
  //
  if (sequenceExpr())
  {
    ((ExpSequenceExpression*)sequenceExpr())->seqFixup
      ((void*)this, GetHistoryRow, GetHistoryRowOLAP);
    sequenceExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob);
  }

  if (returnExpr())
  {
    ((ExpSequenceExpression*)returnExpr())->seqFixup
      ((void*)this, GetHistoryRow, GetHistoryRowFollowingOLAP);
    returnExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob);
  }

  if (postPred())
    postPred()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob);


  if (cancelExpr())
    cancelExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob);

  if (checkPartitionChangeExpr())
  {
    ((ExpSequenceExpression*)checkPartitionChangeExpr())->seqFixup
      ((void*)this, GetHistoryRow, GetHistoryRowOLAP);
    checkPartitionChangeExpr()->fixup(0, getExpressionMode(), this, space, heap_, FALSE, glob);
  }
}
示例#4
0
// work - doit...
//
//
short ExSampleTcb::work()
{
  // If there are no parent requests on the queue, then there cannot
  // be anything to do here.
  //
  if (qparent_.down->isEmpty())
    return WORK_OK;

  ex_queue_entry * pentry_down;
  ExSamplePrivateState * pstate;
  ex_queue::down_request request;

  // Take any new parent requests and pass them on to the child as long
  // as the child's queue is not full. processedInputs_ maintains the 
  // Queue index of the last request that was passed on.
  // 
  for(queue_index tail = qparent_.down->getTailIndex(); 
      (processedInputs_ != tail) && (!qchild_.down->isFull());
      processedInputs_++ )
    {
      pentry_down = qparent_.down->getQueueEntry(processedInputs_);
      pstate = (ExSamplePrivateState*) pentry_down->pstate;
      request = pentry_down->downState.request;

      // If the request has already been cancelled don't pass it to the
      // child. Instead, just mark the request as done. This will trigger
      // a EOD reply when this request gets worked on.
      //
      if (request == ex_queue::GET_NOMORE)
        {
          pstate->step_ = ExSamp_DONE;
        }
      else
        {
          pstate->step_ = ExSamp_PREWORK;

	  // Pass the request to the child
	  //
          ex_queue_entry * centry = qchild_.down->getTailEntry();
          centry->downState.request = ex_queue::GET_ALL;
          centry->downState.requestValue = 11;
          centry->downState.parentIndex = processedInputs_;
          centry->passAtp(pentry_down);
          qchild_.down->insert();

          // Copy the input atp to the work atp for this request
	  //
          pstate->workAtp_->copyAtp(pentry_down->getAtp());
        }
    } // end for processedInputs_

  pentry_down = qparent_.down->getHeadEntry();
  pstate = (ExSamplePrivateState*) pentry_down->pstate;
  request = pentry_down->downState.request;

  // If the request has not been worked on yet, then
  // initialize the presistent expression variable data and
  // switch to the WORKING state.
  //
  if(pstate->step_ == ExSamp_PREWORK)
    {
      pstate->step_ = ExSamp_WORKING;
      if(balanceExpr()) balanceExpr()->initializePersistentData();
    }
  
  ExOperStats *statsEntry = getStatsEntry(); 
  // Take any child replies and process them. Return the processed
  // rows as long the parent queue has room.
  //
  while (1)
    {
      // If we have satisfied the parent request (or it was cancelled),
      // then stop processing rows, cancel any outstanding child
      // requests, and set this request to the CANCELLED state.
      //
      if((pstate->step_ == ExSamp_WORKING) ||
	 (pstate->step_ == ExSamp_RETURNINGROWS))
	{
	  if ((request == ex_queue::GET_NOMORE) ||
	      ((request == ex_queue::GET_N) &&
	       (pentry_down->downState.requestValue 
		<= (Lng32)pstate->matchCount_)))
	    {
	      qchild_.down->cancelRequestWithParentIndex
		(qparent_.down->getHeadIndex());
	      pstate->step_ = ExSamp_CANCELLED;
	    }
	}

      switch (pstate->step_)
	{
	  // ExSamp_CANCELLED
	  //
	  // Transition to this state from ...
	  // 1. ExSamp_Error - After the error has been processed.
	  // 2. ExSamp_Working - If enough rows have been returned.
	  // 3. ExSamp_Working - If the request was cancelled.
	  //
	  // Remain in this state until ..
	  // 1. All rows from the child including EOD are consumed
	  //
	  // Transition from this state to ...
	  // 1. ExSamp_DONE - In all cases.
	  //
	case ExSamp_CANCELLED:
	  {
	    // There are no extra rows to process from the child yet,
	    // so try again later.
	    //
	    if (qchild_.up->isEmpty())
	      {
		return WORK_OK;
	      }

	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    ex_queue::up_status child_status = centry->upState.status;

	    // If this is the EOD, transition to the ExSamp_DONE state.
	    //
	    if (child_status == ex_queue::Q_NO_DATA)
		  pstate->step_ = ExSamp_DONE;

	    // Discard the child row.
	    qchild_.up->removeHead();	    
	    break;
	  }

	// ExSamp_ERROR
	//
	// Transition to this state from ...
	// 1. ExSamp_WORKING - a child reply with the type SQLERROR.
	//
	// Remain in this state until ..
	// 1. The error row has been returned to the parent.
	//
	// Transition from this state to ...
	// 1. ExSamp_CANCELLED - In all cases.
	//
	case ExSamp_ERROR:
	  {
            // If there is no room in the parent queue for the reply,
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    ex_queue_entry *pentry_up = qparent_.up->getTailEntry();
	    ex_queue_entry * centry = qchild_.up->getHeadEntry();

	    // Cancel the child request - there must be a child request in
	    // progress to get to the ExSamp_ERROR state.
	    //
	    qchild_.down->cancelRequestWithParentIndex
	      (qparent_.down->getHeadIndex());

	    // Construct and return the error row.
	    //
            pentry_up->copyAtp(centry);
	    pentry_up->upState.status = ex_queue::Q_SQLERROR;
	    pentry_up->upState.parentIndex 
	      = pentry_down->downState.parentIndex;
	    pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
            pentry_up->upState.setMatchNo(pstate->matchCount_);
            qparent_.up->insert();

	    // Transition to the ExSamp_CANCELLED state.
	    //
	    pstate->step_ = ExSamp_CANCELLED;
	    break;
	  }

	// ExSamp_WORKING
	//
	// Transition to this state from ...
	// 1. ExSamp_EMPTY - If a request is started.
	//
	// Remain in this state until ...
	// 1. All child replies including EOD have been processed.
	// 2. A SQLERROR row is received.
	// 3. Enough rows have been returned.
	// 4. The request is cancelled.
	//
	// Transition from this state to ...
	// 1. ExSamp_DONE - If all the child rows including EOD have 
	//    been processed.
	// 2. ExSamp_ERROR - If an SQLERROR rows is received.
	// 3. ExSamp_CANCELLED - If enough rows have been returned.
	// 3. ExSamp_CANCELLED - If the request is cancelled.
	//
	case ExSamp_WORKING:
	  {
	    // If there is not room in the parent Queue for the reply,
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;

	    // If there are no replies, try again later.
	    //
	    if (qchild_.up->isEmpty())
	      return WORK_OK;

	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    switch (centry->upState.status)
	      {
		
		// A data row from the child.
		//
	      case ex_queue::Q_OK_MMORE:
		{
		  // Apply the sampling predicate if it exists and extract
		  // the sampling factor.
		  //
		  ex_expr::exp_return_type retCode = ex_expr::EXPR_TRUE;
		  Int32 samplingFactor = 1;
		  if(balanceExpr())
		    {
		      retCode = balanceExpr()->eval
			(centry->getAtp(), centry->getAtp());
		      
		      if(retCode == ex_expr::EXPR_OK)
			{
			  samplingFactor = 
			    *(Lng32*)balanceExpr()->getPersistentData
			    (returnFactorOffset());
		      
			  // If the sampling factor is less than 0, then
			  // we are done with this request. Mark the
			  // request as get-no-more. Forces the child to be
                          // cancelled
			  //
			  if(samplingFactor < 0)
			    {
                              // Cancel the rest of this
                              // request.
			      pentry_down->downState.request 
				= ex_queue::GET_NOMORE;
			      request = ex_queue::GET_NOMORE;
                              
                              // Return no rows
			      retCode = ex_expr::EXPR_FALSE;
			    }
			}
		    }
		  
		  // If the row passed the sampling predicate, apply the 
		  // selection predicate if it exists.
		  //
		  if ((samplingFactor > 0) && 
		      (retCode == ex_expr::EXPR_OK) && 
		      postPred()) 
		    retCode = postPred()->eval
		      (centry->getAtp(), centry->getAtp());

		  // Act on the result of the selection predicate.
		  //
		  switch(retCode) {
		    // If the selection predicate returns TRUE,
		    // return the row to the parent the number
		    // of times indicated by the sampling factor as long
		    // as there is room in the parent queue.
		    //
		  case ex_expr::EXPR_TRUE:
		  case ex_expr::EXPR_OK:
		    while(!qparent_.up->isFull() && (samplingFactor > 0))
		      {
			// Copy the child ATP to the parent ATP -- the 
			// row images are exactly the same.
			//
			ex_queue_entry * pentry_up 
			  = qparent_.up->getTailEntry();
			pentry_up->copyAtp(centry);

			// Fixup the up state.
			//
			pentry_up->upState.status = ex_queue::Q_OK_MMORE;
			pentry_up->upState.parentIndex 
			  = pentry_down->downState.parentIndex;
			pentry_up->upState.downIndex 
			  = qparent_.down->getHeadIndex();
			pstate->matchCount_++;
			pentry_up->upState.setMatchNo(pstate->matchCount_);

			// Commit the entry.
			//
			qparent_.up->insert();
                        if (statsEntry)
                           statsEntry->incActualRowsReturned();
			samplingFactor--;

			// If we have satisfied a GET_N request, then
			// break out of here so we can stop processing.
			//
			if((request == ex_queue::GET_N) &&
			   (pentry_down->downState.requestValue 
			    <= (Lng32)pstate->matchCount_))
			  {
			    samplingFactor = 0;
			    break;
			  }
		      }

		    // If all of the rows are returned, then we are done
		    // with this entry and can proceed. 
		    //
		    if(samplingFactor == 0)
		      {
			qchild_.up->removeHead();
		      }
		    // Otherwise, the queue must have become full so we 
		    // have to switch to the RETURNINGROWS state to finish 
		    // the job.
		    else
		      {
			pstate->rowsToReturn_ = samplingFactor;
			pstate->step_ = ExSamp_RETURNINGROWS;
			return WORK_OK;
		      }
		      
		    break;
		    
		    // If the selection predicate returns FALSE,
		    // do not return the child row.
		    //
		  case ex_expr::EXPR_FALSE:
		    qchild_.up->removeHead();
		    break;

		    // If the selection predicate returns an ERROR,
		    // go to the error processing state.
		    //
		  case ex_expr::EXPR_ERROR:
		    pstate->step_ = ExSamp_ERROR;
		    break;
		  }
		}
		break;

		// The EOD from the child. Transition to ExSamp_DONE.
		//
	      case ex_queue::Q_NO_DATA:
		pstate->step_ = ExSamp_DONE;
		qchild_.up->removeHead();
		break;

		// An SQLERROR from the child. Transition to ExSamp_ERROR.
		//
	      case ex_queue::Q_SQLERROR:
		pstate->step_ = ExSamp_ERROR;
		break;
	      }
	  }
	break;

	// ExSamp_RETURNINGROWS
	//
	// Transistion to this state from ...
	// 1. ExSamp_WORKING - if up queue becomes full when returning 
	//                    multiple rows from oversampling.
	//
	// Remain in this state until ...
	// 1. the multiple oversampled rows have been returned.
	//
	case ExSamp_RETURNINGROWS:
	  {
	    ex_queue_entry * centry = qchild_.up->getHeadEntry();
	    while(!qparent_.up->isFull() && (pstate->rowsToReturn_ > 0))
	      {
		// Copy the child ATP to the parent ATP -- the row
		// images are exactly the same.
		//
		ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
		pentry_up->copyAtp(centry);
		
		// Fixup the up state.
		//
		pentry_up->upState.status = ex_queue::Q_OK_MMORE;
		pentry_up->upState.parentIndex 
		  = pentry_down->downState.parentIndex;
		pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
		pstate->matchCount_++;
		pentry_up->upState.setMatchNo(pstate->matchCount_);
		
		// Commit the entry.
		//
		qparent_.up->insert();
                if (statsEntry)
                   statsEntry->incActualRowsReturned();

		pstate->rowsToReturn_--;

		// If we have satisfied a GET_N request, then
		// break out of here so we can stop processing.
		//
		if((request == ex_queue::GET_N) &&
		   (pentry_down->downState.requestValue 
		    <= (Lng32)pstate->matchCount_))
		  {
		    pstate->rowsToReturn_ = 0;
		    break;
		  }
	      }

	    // If all of the rows were returned, remove the child's reply
	    // and go back to the WORKING state.
	    //
	    if(pstate->rowsToReturn_ == 0)
	      {
		qchild_.up->removeHead();
		pstate->step_ = ExSamp_WORKING;
	      }
	    // Otherwise, we need to come back later to finish up.
	    //
	    else
	      {
		return WORK_OK;
	      }
	  }
	break;

	// ExSamp_DONE
	//
	// Transition to the state from ...
	// 1. ExSamp_WORKING - if all child rows have been processed.
	// 2. ExSamp_CANCELLED - if all child rows have been consumed.
	// 3. ExSamp_EMPTY - if the request was DOA.
	//
	// Remain in this state until ...
	// 1. The EOD is returned to the parent.
	//
	// Transition from this state to ...
	// 1. ExSamp_EMPTY - In all cases.
	//
	case ExSamp_DONE:
	  {
	    // If there is not any room in the parent's queue, 
	    // try again later.
	    //
	    if (qparent_.up->isFull())
	      return WORK_OK;
	    
	    ex_queue_entry * pentry_up = qparent_.up->getTailEntry();
	    pentry_up->upState.status = ex_queue::Q_NO_DATA;
	    pentry_up->upState.parentIndex 
	      = pentry_down->downState.parentIndex;
	    pentry_up->upState.downIndex = qparent_.down->getHeadIndex();
	    pentry_up->upState.setMatchNo(pstate->matchCount_);
	    
	    qparent_.down->removeHead();
	    qparent_.up->insert();

            // Re-initialize pstate
	    //
	    pstate->step_ = ExSamp_EMPTY;
            pstate->matchCount_ = 0;
	    pstate->rowsToReturn_ = 0;
            pstate->workAtp_->release();

	    // If there are no more requests, simply return.
	    //
            if (qparent_.down->isEmpty())
              return WORK_OK;

            // If we haven't given to our child the new head
            // index return and ask to be called again.
	    //
            if (qparent_.down->getHeadIndex() == processedInputs_)
	      return WORK_CALL_AGAIN;

            // Postion at the new head of the request queue.
	    //
            pentry_down = qparent_.down->getHeadEntry();
            pstate = (ExSamplePrivateState*) pentry_down->pstate;
            request = pentry_down->downState.request;

	    // If the request has not been worked on yet, then initialize the
	    // presistent expression variable data and switch to the 
	    // WORKING state.
	    //
	    if(pstate->step_ == ExSamp_PREWORK)
	      {
		pstate->step_ = ExSamp_WORKING;
		if(balanceExpr()) balanceExpr()->initializePersistentData();
	      }
	  }
	break;
	} // switch pstate->step_
    } // while
}