blob: 480d39b12843eca5737ef6e659a2f536676cb1ca [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: /executor/ex_timeout.cpp
* Description: Implement methods of ExTimeoutTdb, ExTimeoutTcb
*
* Created: 12/27/1999
* Language: C++
*
*
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "cli_stdh.h"
#include "ex_stdh.h"
#include "ComTdb.h"
#include "ex_tcb.h"
#include "ex_timeout.h"
#include "ex_root.h"
#include "ex_exe_stmt_globals.h"
#include "exp_expr.h"
#include "ex_error.h"
#include "ExSqlComp.h"
#include "timeout_data.h"
/////////////////////////////////////////////////////////////////
// class ExTimeoutTdb, ExTimeoutTcb, ExTimeoutPrivateState
/////////////////////////////////////////////////////////////////
ex_tcb * ExTimeoutTdb::build(ex_globals * glob)
{
ExTimeoutTcb * timeout_tcb =
new(glob->getSpace()) ExTimeoutTcb(*this, (ExMasterStmtGlobals *)glob);
timeout_tcb->registerSubtasks();
return (timeout_tcb);
}
////////////////////////////////////////////////////////////////
// Constructor for class ExTimeoutTcb
///////////////////////////////////////////////////////////////
ExTimeoutTcb::ExTimeoutTcb(const ExTimeoutTdb & timeout_tdb,
ExMasterStmtGlobals * glob)
: ex_tcb( timeout_tdb, 1, glob)
{
Space * space = (glob ? glob->getSpace() : 0);
CollHeap * heap = (glob ? glob->getDefaultHeap() : 0);
// Allocate the buffer pool
pool_ = new(space) sql_buffer_pool(timeout_tdb.numBuffers_,
timeout_tdb.bufferSize_,
space);
// Allocate the queue to communicate with parent
qparent_.down = new(space) ex_queue(ex_queue::DOWN_QUEUE,
timeout_tdb.queueSizeDown_,
timeout_tdb.criDescDown_,
space);
// Allocate the private state in each entry of the down queue
ExTimeoutPrivateState *p = new(space) ExTimeoutPrivateState(this);
qparent_.down->allocatePstate(p, this);
delete p;
qparent_.up = new(space) ex_queue(ex_queue::UP_QUEUE,
timeout_tdb.queueSizeUp_,
timeout_tdb.criDescUp_,
space);
// Get the name of the table from the late-name-info in the root-tdb
ex_root_tdb * rootTdb = (ex_root_tdb *) glob->getFragmentPtr(0) ;
LateNameInfoList * lnil = rootTdb->getLateNameInfoList();
ex_assert( lnil , "No late name info list in root TDB!");
theTableName_ = lnil->getLateNameInfo(0).resolvedPhyName();
ex_assert( theTableName_ , "No table name !");
if (timeoutValueExpr()) {
// allocate work atp to compute the timeout value
workAtp_ = allocateAtp(timeout_tdb.workCriDesc_, space);
// allocate tuple where the timeout value will be moved
pool_->get_free_tuple(workAtp_->
getTupp(timeout_tdb.workCriDesc_->noTuples() - 1),
sizeof(Lng32));
(void) timeoutValueExpr()->fixup(0, getExpressionMode(), this,
space, heap, FALSE, glob);
}
else
workAtp_ = 0;
}
// dtor
ExTimeoutTcb::~ExTimeoutTcb()
{
delete qparent_.up;
delete qparent_.down;
delete pool_;
pool_ = 0;
};
//////////////////////////////////////////////////////
// work() for ExTimeoutTcb
//////////////////////////////////////////////////////
short ExTimeoutTcb::work()
{
while (1) {
// if no parent request, return
if (qparent_.down->isEmpty())
return WORK_OK;
// if no room in up queue, won't be able to return data/status.
// Come back later.
if (qparent_.up->isFull()) return WORK_OK;
ex_queue_entry * pentry_down = qparent_.down->getHeadEntry();
ExTimeoutPrivateState & pstate =
*((ExTimeoutPrivateState*) pentry_down->pstate);
// Calculate the timeout actual value
Lng32 timeoutValue = 0;
NABoolean goodTimeoutValue = TRUE ;
if (timeoutValueExpr()) {
if ( timeoutValueExpr()->eval(pentry_down->getAtp(), workAtp_)
== ex_expr::EXPR_ERROR ) { // expression did not yield a valid value
handleErrors(pentry_down, pentry_down->getAtp()->getDiagsArea());
goodTimeoutValue = FALSE ;
} else {
tupp TP = workAtp_->getTupp(timeoutTdb().workCriDesc_->noTuples()-1);
timeoutValue = *(Lng32 *)TP.getDataPointer(); // pointer is (char *)
}
}
/****************************************************/
/******** Do the actual SET TIMEOUT work ********/
/** **/
/** The scope of the work is only making changes **/
/** to the global timeout data kept at the context **/
/****************************************************/
// Get the global timeout-data object
ContextCli * currContext = getGlobals()->castToExExeStmtGlobals()->
castToExMasterStmtGlobals()->getStatement()->getContext();
TimeoutData * GlobalTimeouts = currContext->getTimeouts();
#if _DEBUG // For debugging only !!!!!
if ( getenv("DEBUG_TIMEOUT") ) {
ComDiagsArea* diagsArea =
ComDiagsArea::allocate (getGlobals()->getDefaultHeap());
char errmsg[120];
if ( timeoutTdb().isStream() ) { // it was a SET STREAM TIMEOUT
if ( GlobalTimeouts->isStreamTimeoutSet() ) {
sprintf(errmsg, "Stream timeout set to %d\n",
GlobalTimeouts->getStreamTimeout() );
} else sprintf(errmsg, "Stream timeout was NOT SET ! \n");
} // lock timeout -- not stream
else {
if ( theTableName_[0] == '*' ) { // For all tables
sprintf(errmsg, "Number of lock timeouts set: %d\n",
GlobalTimeouts->entries() );
} else {
Lng32 timeoutValue;
NABoolean found =
GlobalTimeouts->getLockTimeout(theTableName_, timeoutValue );
if ( ! found )
sprintf(errmsg, "Lock timeout for table %s was NOT SET ! \n",
theTableName_ );
else sprintf(errmsg, "Lock timeout for table %s is %d \n",
theTableName_ , timeoutValue );
}
}
// emit message as an error ( msg 3066 has no text of its own )
*diagsArea << DgSqlCode(-3066)
<< DgString0(errmsg) ;
ExHandleArkcmpErrors(qparent_, pentry_down, 0, getGlobals(),
diagsArea, (ExeErrorCode) -3066 );
} // end of debugging section
else
#endif
if ( goodTimeoutValue ) {
// Update the globals as needed
if ( timeoutTdb().isStream() ) { // it was a SET STREAM TIMEOUT
if ( timeoutTdb().isReset() ) // it was a RESET
GlobalTimeouts->resetStreamTimeout();
else // it was a SET (with a value)
GlobalTimeouts->setStreamTimeout(timeoutValue);
}
else { // setting a LOCK TIMEOUT
// TBD =============>>> Check if FORALL string includes CAT.SCH ......
if ( theTableName_[0] == '*' ) { // For all tables
if ( timeoutTdb().isReset() ) // it was a RESET
GlobalTimeouts->resetAllLockTimeout();
else GlobalTimeouts->setAllLockTimeout(timeoutValue);
}
else { // per specific table
if ( timeoutTdb().isReset() ) // it was a RESET
GlobalTimeouts->resetTableLockTimeout( theTableName_ );
else GlobalTimeouts->setTableLockTimeout(theTableName_,timeoutValue);
}
}
// execution of every SET TIMEOUT stmt increments the change counter !!
currContext->incrementTimeoutChangeCounter();
// clear up (i.e. deallocate) the global timeout data, if possible
if ( GlobalTimeouts->noLockTimeoutsSet() &&
! GlobalTimeouts->isStreamTimeoutSet() )
currContext->clearTimeoutData();
} // end of if ( goodTimeoutValue )
/********** at this point the actual work is done ******************/
// all ok. Return EOF.
ex_queue_entry * up_entry = qparent_.up->getTailEntry();
up_entry->upState.parentIndex =
pentry_down->downState.parentIndex;
up_entry->upState.setMatchNo(0);
up_entry->upState.status = ex_queue::Q_NO_DATA;
// insert into parent
qparent_.up->insert();
qparent_.down->removeHead();
}
return WORK_OK;
}
// if diagsArea is not NULL, then its error code is used.
// Otherwise, err is used to handle error.
void ExTimeoutTcb::handleErrors(ex_queue_entry *pentry_down,
ComDiagsArea *da,
ExeErrorCode err)
{
ExHandleArkcmpErrors(qparent_, pentry_down, 0, getGlobals(), da, err);
}
//////////////////////////////////////////////////////////////////////////////
// Constructor and destructor for Lock_private_state
//////////////////////////////////////////////////////////////////////////////
ExTimeoutPrivateState::ExTimeoutPrivateState(const ExTimeoutTcb * /*tcb*/)
{
}
ExTimeoutPrivateState::~ExTimeoutPrivateState()
{
};
ex_tcb_private_state * ExTimeoutPrivateState::allocate_new(const ex_tcb *tcb)
{
return new(((ex_tcb *)tcb)->getSpace())
ExTimeoutPrivateState((ExTimeoutTcb *) tcb);
};