Beispiel #1
0
int
gcadm_format_err_data( char * buffer, char * sqlstate, i4 error_code, 
	    i4 error_len, char * error_text )
{
    char   *er_data;
    i4     one = 1, zero = 0;
    i4     data_type = DB_CHA_TYPE;
    i4     ss_code, severity = GCA_ERFORMATTED;
    i4     msg_len;


    if ( GCADM_global.gcadm_trace_level >= 5 )
	TRdisplay( "%4d   GCADM format_err_data:  error_code= %d\n",						 -1, error_code );
    /* 
    ** Set default sqlstate
    */
    if (  sqlstate  == NULL )
	sqlstate = SS50000_MISC_ERRORS;

    ss_code = ss_encode( sqlstate );

    /* 
    ** Format GCA_ER_DATA object  
    */
    er_data = (char *) buffer;
    if ( ( error_code == FAIL ) || ( error_code == OK )) 
	er_data += GCA_PUTI4_MACRO( &zero, er_data);	/* gca_l_e_element */
    else 	
    {
	er_data += GCA_PUTI4_MACRO( &one, er_data);	/* gca_l_e_element */
	er_data += GCA_PUTI4_MACRO( &ss_code, er_data );/* gca_id_error */ 
	er_data += GCA_PUTI4_MACRO( &zero, er_data); 	/* gca_id_server */
	er_data += GCA_PUTI4_MACRO( &zero, er_data); 	/* gca_server_type */
	er_data += GCA_PUTI4_MACRO( &severity, er_data );/* gca_serverity */
	er_data += GCA_PUTI4_MACRO( &error_code, er_data);/* gca_local_error */

	/* 
	** Check to see if there is error text 
	*/
	if ( error_len == 0  ||  ! error_text )
	    er_data += GCA_PUTI4_MACRO( &zero, er_data);/* gca_l_error_parm */
	else
	{
	    er_data += GCA_PUTI4_MACRO( &one, er_data);	/* gca_l_error_parm */
	    er_data += GCA_PUTI4_MACRO( &data_type, er_data );   /* gca_type */
	    er_data += GCA_PUTI4_MACRO( &zero, er_data );    /* gca_precision */

	/* 
	** Calculate the message len to ensure not over max buffer len  
	*/
	    msg_len = er_data - (char *)buffer + sizeof(i4);	
	    if ( (error_len + msg_len) > GCADM_global.gcadm_buff_len )
		  error_len = GCADM_global.gcadm_buff_len - msg_len;

	    er_data += GCA_PUTI4_MACRO( &error_len, er_data);  /* gca_l_value */
	    er_data += GCA_PUTBUF_MACRO( error_text, error_len, er_data);
							    /* gca_value */
	}
    }

    return( er_data - (char *)buffer );  
    
}
Beispiel #2
0
static void
gcadm_complete( PTR ptr )
{
    GCADM_RCB	*rcb = (GCADM_RCB *)ptr;  
    GCADM_SCB   *scb = rcb->scb;
    
    /*
    ** Check for request failure or convert request
    ** type to the associated request completion.  
    ** if term state, we don't care if request is complete or failed 
    ** return to caller.    
    **
    */

    if ( scb->parms.gca_all_parm.gca_status == E_GCFFFE_INCOMPLETE )
    {
 	gcadm_resume ( rcb );
	return; 
    }

    if ( GCADM_global.gcadm_state != GCADM_ACTIVE )
    {
	if ( GCADM_global.gcadm_trace_level >= 1 )
	    TRdisplay( "%4d   GCADM complete: ADM not active\n", -1 );
	if ( rcb->operation ==  GCA_DISASSOC )
	    gcadm_free_scb( scb );
	gcadm_free_rcb( rcb );
	return; 
    }

    if ( GCADM_global.gcadm_trace_level >= 4 )
	TRdisplay( "%4d   GCADM complete: entry\n", scb->aid);

    if ( GCADM_global.gcadm_trace_level >= 5 )
	TRdisplay( "%4d   GCADM complete: GCA operation= %d, status =%d\n", 
		scb->aid, rcb->operation,
		scb->parms.gca_all_parm.gca_status );

    if ( scb->parms.gca_all_parm.gca_status != OK)    
    {
	if ( GCADM_global.gcadm_trace_level >= 1 )
	    TRdisplay( "%4d   GCADM complete: GCA operation= %d failed \n", 
		scb->aid, rcb->operation );
	rcb->event = ADMI_RQST_FAIL;
    	rcb->status = scb->parms.gca_all_parm.gca_status;
	gcadm_event( rcb );
	return;
    }
	
    switch( rcb->operation )
    {
	case GCA_RECEIVE : 
	    switch (scb->parms.gca_rv_parm.gca_message_type)
	    {
	    case GCA_RELEASE:  
		rcb->event = ADMI_RECV_RELEASE;
		break;
	    case GCA_MD_ASSOC:
		rcb->event = ADMI_RECV_MDASSOC;
		break;
	    case GCA_QUERY:
		rcb->event = ADMI_RECV_QUERY;
		break;
	    default:
		if ( GCADM_global.gcadm_trace_level >= 1 )
		   TRdisplay( "%4d   GCADM complete: recv unexpected msg %d \n", 	            scb->aid, scb->parms.gca_rv_parm.gca_message_type); 
		rcb->status = E_GC5004_INVALID_MSG;
		rcb->event = ADMI_RECV_INVALID;
		break;
	    }
	    break;	

	case GCA_SEND: 
	    rcb->event = ADMI_SEND_CMPL; 
	    break;

	case GCA_DISASSOC: 
 	    rcb->event = ADMI_DISC_DONE; 
	    break;  
			
	default :
	    rcb->status = E_GC5005_INTERNAL_ERROR;
	    rcb->event = ADMI_RQST_FAIL;
	    return;
    }

    gcadm_event( rcb );
    return;

}
Beispiel #3
0
/*
** Name: sxapo_init_cnf - Initialize SXAPO configuration from the PM file.
**
** Description:
**	This routine initializes the SXAPO configuration from the
**	PM configuration file.
**
** Inputs:
**	None.
**
** Outputs:
**	err_code		Error code returned to caller.
**
** Returns:
**	DB_STATUS
**
** History:
**	6-jan-94 (stephenb)
**	    Initial creation.
*/
DB_STATUS
sxapo_init_cnf(
	i4		*err_code)
{
    DB_STATUS		status = E_DB_OK;
    STATUS		clstat;
    i4		local_err;
    char		*pmfile;
    char		*pmvalue;

    *err_code = E_SX0000_OK;
    for (;;)
    {
    	/*
    	** Allow private override on PM file
    	*/
	NMgtAt("II_SXF_PMFILE", &pmfile);
	if (pmfile && *pmfile)
	{
		LOCATION	pmloc;
		TRdisplay("Loading SXF-PM file '%s'\n",pmfile);
		LOfroms(PATH & FILENAME, pmfile, &pmloc);
		if(PMload(&pmloc,NULL)!=OK)
		TRdisplay("Error loading PMfile '%s'\n",pmfile);
	}
	/*
	** Get auditing status
	*/
	if (PMget(SX_C2_MODE,&pmvalue) == OK)
	{
		if (!STbcompare(pmvalue, 0, SX_C2_MODE_ON, 0, TRUE))
		{
		    /*
		    ** Auditing on
		    */
		    Sxapo_cb->sxapo_status=SXAPO_ACTIVE;
		}
		else if ((STbcompare(pmvalue, 0, SX_C2_MODE_OFF, 0, TRUE)!=0))
		{
		    /*
		    ** Niether ON nor OFF, Invalid mode
		    */
		    *err_code=E_SX1061_SXAP_BAD_MODE;
		    break;
		}
	}
	else
	{
		/*
		** No value, this is an error
		*/
		*err_code=E_SX1061_SXAP_BAD_MODE;
		break;
	}
	/*
	** Get action on error
	*/
	if ((PMget("II.*.C2.ON_ERROR",&pmvalue) == OK))
	{
		if (!STcasecmp(pmvalue, "STOPAUDIT" ))
		{
		    Sxf_svcb->sxf_act_on_err=SXF_ERR_STOPAUDIT;
		}
		else if (!STcasecmp(pmvalue, "SHUTDOWN" ))
		{
		    Sxf_svcb->sxf_act_on_err=SXF_ERR_SHUTDOWN;
		}
		else
		{
		/*
		** Invalid value
		*/
		*err_code=E_SX1060_SXAP_BAD_ONERROR;
		break;
		}
	}
	else
	{
		/*
		** No value, this is an error
		*/
		*err_code=E_SX1060_SXAP_BAD_ONERROR;
		break;
	}
	break;
    }
    /* handle errors */
    if (*err_code != E_SX0000_OK)
    {
	_VOID_ ule_format(*err_code, NULL, ULE_LOG, NULL, NULL,
		0L, NULL, &local_err, 0);
	*err_code = E_SX1020_SXAP_INIT_CNF;
	status = E_DB_ERROR;
    }
    return (status);
}
Beispiel #4
0
void IIodbc_timeOutThread()
{
    QUEUE *q, *p, *pq;
    pENV penv;
    pDBC pdbc;
    RETCODE rc;
    SYSTIME expire_time;
    TM_STAMP stamp;
    char stampStr[TM_SIZE_STAMP];

    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
        ("IIodbc_timeOutThread() with timeout %d\n", IIodbc_cb.timeout);
    while(TRUE)
    {
        /*
        ** Search the pool every thirty seconds and check for expired
        ** connections.  Force disconnect and free from the pool
        ** if the connection handle has passed the expiration time.  
        ** Note that the CLI and driver connection handles are not
        ** freed.  
        */
        PCsleep(30000);
        TMget_stamp(&stamp);
        TMstamp_str(&stamp, stampStr);
        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
            ("IIodbc_timeOutThread woke up at %s\n", stampStr);
        TMnow(&expire_time);
        
        if (IIodbc_cb.pooling == DRIVER_POOL)
        {
            applyLock(SQL_HANDLE_IIODBC_CB, NULL);
            for (q = IIodbc_cb.pool_q.q_prev; q!= &IIodbc_cb.pool_q;
                q = p)
            {
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: driver pool count is %d\n", 
                    IIodbc_cb.pool_count);
                p = q->q_prev;
                pdbc = (pDBC)((pPOOL)q)->pdbc;
                ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                    ("IIodbc_timeOutThread: found conn handle %p with time diff %d\n",pdbc,
                    expire_time.TM_secs - pdbc->expire_time.TM_secs);
                if (expire_time.TM_secs - pdbc->expire_time.TM_secs > 
                    IIodbc_cb.timeout)
                {
                    /*
                    **  Note that the connection handle is not freed, only
                    **  removed from the pool. 
                    */
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                        pdbc->expire_time.TM_secs, expire_time.TM_secs);
                    rc = IIDisconnect(pdbc->hdr.driverHandle);
                    QUremove(q);
                    MEfree((PTR)q);
                    IIodbc_cb.pool_count -= 1;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("new pool count is %d\n",IIodbc_cb.pool_count);
                    applyLock(SQL_HANDLE_DBC, pdbc);
                    pdbc->hdr.state = C2;
                    releaseLock(SQL_HANDLE_DBC, pdbc);
                }
            }
            releaseLock(SQL_HANDLE_IIODBC_CB, NULL);
        }
        else
        {
            for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev)
            {
                penv = (pENV)q;
                TRdisplay("Found env handle %p\n",penv);
                applyLock(SQL_HANDLE_ENV, penv);
                for (pq = penv->pool_q.q_prev; pq != &penv->pool_q;
                    pq = p)
                {
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("Env pool count is %d\n",penv->pool_count);
                    p = q->q_prev;
                    pdbc = (pDBC)((pPOOL)pq)->pdbc;
                    ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                        ("IIodbc_TimeOutThread: Found conn handle %p with time diff %d\n",pdbc,
                        expire_time.TM_secs - pdbc->expire_time.TM_secs);
                    if (expire_time.TM_secs - pdbc->expire_time.TM_secs
                        > 1)
                    {
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: EXPIRED.  pdbc time is %d vs %d\n",
                            pdbc->expire_time.TM_secs,   
                            expire_time.TM_secs);
                        rc = IIDisconnect(pdbc->hdr.driverHandle);
                        QUremove(q);
                        MEfree((PTR)q);
                        penv->pool_count -= 1;
                        ODBC_EXEC_TRACE(ODBC_EX_TRACE)
                            ("IIodbc_timeOutThread: new pool count is %d\n",
                            penv->pool_count);
                    }
                }
                releaseLock(SQL_HANDLE_ENV, penv);
            } /* for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q;
                q = q->q_prev) */
        } /* if (IIodbc_cb.pooling == DRIVER_POOL) */
    } /* while (TRUE) */
}
Beispiel #5
0
/*{
**
** Name: dmc_write_behind_common  -  the guts of a write behind thread
**
** Description:
**
**	The dmc_write_behind routine is used for implementing an asynchronous
**	write behind thread.  It wakes up whenever signaled by an LK event
**	and writes dirty pages out of the cache to make room for new pages
**	to be read in.
**
**	The dmc_write_behind routine should only be called within a special
**	session that is dedicated for this purpose.  This routine will not
**	return under normal circumstances until server shutdown time.
**
**	This routine uses two routines in DM0P to drive the write behind
**	thread:
**	    DM0P_BMFLUSH_WAIT waits for a session in the buffer manager
**	    to signal the event to wake up the write behind threads.  This
**	    is signalled when some specified percent of the buffer manager
**	    is filled with dirty pages.
**
**	    DM0P_FLUSH_PAGES goes through the buffer manager modified queue
**	    in reverse priority order writing pages until some specified
**	    percentage of the buffer manager is free.
**
**	This routine will return only if the event wait in DM0P_BMFLUSH_WAIT
**	is cancelled by an interrupt.  At server shutdown time, the server
**	is expected to interrupt all the write behind threads.
**
**	This common code is executed by both Primary and Cloned
**	WriteBehind agents.
**
** Inputs:
**	i_am_a_clone		FALSE if this is the Primary WB Agent,
**				TRUE if a Clone.
**	cfa			Agent's data.
**
** Outputs:
**     dmf_err
** 	.error.err_code	    One of the following error numbers.
**			    E_DB_OK
**			    E_DM004A_INTERNAL_ERROR
**			    E_DM004B_LOCK_QUOTA_EXCEED
**			    E_DM0062_TRAN_QUOTA_EXCEED
**			    E_DM0117_WRITE_BEHIND
**
** Returns:
**     E_DB_OK
**     E_DB_FATAL
**
** History:
**      30-jun-1988 (rogerk)
**          Created for Jupiter.      
**      30-Jan-1989 (ac)
**          Added arguments to LGbegin().      
**	15-may-1989 (rogerk)
**	    Return resource errors if resource limit is exceeded.
**      2-oct-1992 (ed)
**          Use DB_MAXNAME to replace hard coded numbers
**          - also created defines to replace hard coded character strings
**          dependent on DB_MAXNAME
**	18-oct-1993 (rogerk)
**	    Add check for LOGFULL status.  We don't execute write behind when
**	    in logfull to avoid background log forces which wreak havoc on
**	    the recovery logspace reservation algorithms.
**	10-oct-93 (swm)
**	    Bug #56438
**	    Put LG_DBID into automatic variable lg_dbid rather than overloading
**	    dmc_cb->dmc_db_id.
**	31-jan-1994 (bryanp) B58380, B58381
**	    Log LG/LK status code if LG or LK call fails.
**	    Check return code from CSsuspend.
**	10-Mar-1998 (jenjo02)
**	    Support for demand-driven WriteBehind threads. Changed prototype
**	    to pass a boolean indicating whether this is the primary or
**	    cloned WB thread and a pointer to DB_ERROR instead of a pointer
**	    to DMC_CB.
**	    Made this a common function called by Primary and Cloned threads.
*/
static DB_STATUS
dmc_write_behind_common(
i4	    i_am_a_clone,
char	    *cfa,
DB_ERROR    *dmf_err)
{
    DM_SVCB	    *svcb = dmf_svcb;
    DB_TRAN_ID	    tran_id;
    LG_LXID	    lx_id;
    DM0L_ADDDB	    add_info;
    TIMERSTAT	    stat_block;
    i4	    lock_list;
    i4		    len_add_info;
    i4		    event_mask;
    i4		    events, wakeup_event;
    i4		    have_locklist = FALSE;
    i4		    have_transaction = FALSE;
    i4		    lg_added = FALSE;
    DB_STATUS	    status = E_DB_OK;
    i4	    wbcount = 0;
    i4	    wait_time = 0;
    i4	    base_time = 0;
    i4	    flush_time, new_time;
    i4	    length;
    i4	    lgd_status;
    STATUS	    stat;
    i4	    error;
    CL_ERR_DESC	    sys_err;
    DB_OWN_NAME	    user_name;
    LG_DBID	    lg_dbid;

#ifdef xDEBUG
    CS_SID	sid;
    i4	pid;

    PCpid(&pid);
    CSget_sid(&sid);

    TRdisplay("Starting Write Behind Thread %x in server process %d\n",
	sid, pid);
#endif

    CLRDBERR(dmf_err);

    if (status == E_DB_OK)
    {
	/*
	** Add write behind thread to logging system.
	** Write behind thread does not actually open a database, so use
	** the LG_NOTDB flag.
	*/
	STmove((PTR)DB_WRITEBEHIND_THREAD, ' ', sizeof(add_info.ad_dbname),
	    (PTR) &add_info.ad_dbname);
	MEcopy((PTR)DB_INGRES_NAME, sizeof(add_info.ad_dbowner),
	    (PTR) &add_info.ad_dbowner);
	MEcopy((PTR)"None", 4, (PTR) &add_info.ad_root);
	add_info.ad_dbid = 0;
	add_info.ad_l_root = 4;
	len_add_info = sizeof(add_info) - sizeof(add_info.ad_root) + 4;

	stat = LGadd(dmf_svcb->svcb_lctx_ptr->lctx_lgid, LG_NOTDB,
	    (char *)&add_info, 
	    len_add_info, &lg_dbid, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900A_BAD_LOG_DBADD, &sys_err, ULE_LOG, NULL,
		(char *)NULL, 0L, (i4 *)NULL, &error, 4, 0,
		dmf_svcb->svcb_lctx_ptr->lctx_lgid,
		sizeof(add_info.ad_dbname), (PTR) &add_info.ad_dbname,
		sizeof(add_info.ad_dbowner), (PTR) &add_info.ad_dbowner,
		4, (PTR) &add_info.ad_root);
	    if (stat == LG_EXCEED_LIMIT)
		SETDBERR(dmf_err, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	    else
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
	    status = E_DB_ERROR;
	}
	else
	    lg_added = TRUE;
    }

    if (status == E_DB_OK)
    {
	/*
	** Begin transaction in order to do LG and LK calls.
	** Must specify NOPROTECT transaction so that LG won't pick us
	** as a force-abort victim.  Also, the Log File BOF can be advanced
	** past this transaction's position in the log file, which means that
	** the Write Behind thread should do no logging nor work that could
	** require backout.
	*/
	STmove((PTR)DB_WRITEBEHIND_THROWN, ' ', sizeof(DB_OWN_NAME), 
							(PTR) &user_name);
	stat = LGbegin(LG_NOPROTECT, lg_dbid, &tran_id, &lx_id,
	    sizeof(DB_OWN_NAME), user_name.db_own_name, 
	    (DB_DIS_TRAN_ID*)NULL, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900C_BAD_LOG_BEGIN, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 
		0, lg_dbid);
	    if (stat == LG_EXCEED_LIMIT)
		SETDBERR(dmf_err, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	    else
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
	    status = E_DB_ERROR;
	}
	else
	    have_transaction = TRUE;
    }

    if (status == E_DB_OK)
    {
	/*
	** Create locklist to use to wait for Write Behind event.
	*/
	stat = LKcreate_list(LK_NONPROTECT, (i4) 0,
	    (LK_UNIQUE *)&tran_id, (LK_LLID *)&lock_list, (i4)0, 
	    &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM901A_BAD_LOCK_CREATE, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    if (stat == LK_NOLOCKS)
		SETDBERR(dmf_err, 0, E_DM004B_LOCK_QUOTA_EXCEEDED);
	    else
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
	    status = E_DB_ERROR;
	}
	else
	    have_locklist = TRUE;
    }

    if (status == E_DB_OK)
    {
	/*
	** Now begin loop of waiting for Write Behind event and flushing
	** the buffer manager.
	*/
	do
	{
	    if (DMZ_ASY_MACRO(2))
	    {
		new_time = TMsecs();
		flush_time = new_time - base_time - wait_time;
		base_time = new_time;

		/* Write Write Behind thread statistics. */
		stat = CSstatistics(&stat_block, 0);
		TRdisplay("%22*- DMF Write Behind Thread statistics %21*-\n");
		TRdisplay("    Write Behind wakeups: %d    Cpu : %d    Dio : %d\n",
		    wbcount, stat_block.stat_cpu, stat_block.stat_dio);
		TRdisplay("    Time waiting for event: %d seconds\n",
		    wait_time);
		TRdisplay("    Time to flush pages: %d seconds\n",
		    flush_time);
		TRdisplay("%79*-\n");
	    }

	    /*
	    ** Cloned threads don't wait for a signal, they just
	    ** help flush the cache, then go away.
	    */
	    if (i_am_a_clone == FALSE)
	    {
		/*
		** Wait for the next signal that the buffer manager needs to have
		** pages flushed.
		**
		** This routine will also clear the event from the previous 
		** signal.
		*/
		status = dm0p_wbflush_wait(cfa, lock_list, dmf_err);
		if (status != E_DB_OK)
		{
		    /*
		    ** If warning is returned, that's a signal that
		    ** this thread is to terminate.
		    */
		    if (status == E_DB_WARN)
		    {
			status = E_DB_OK;
			break;
		    }
		    else
		    {
			if (dmf_err->err_code > E_DM_INTERNAL)
			{
			    uleFormat(dmf_err, 0, NULL, ULE_LOG, NULL, 
			    	(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
			    SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
			}
			break;
		    }
		}
	    }

	    /*
	    ** Check LOGFULL status.  We don't execute write behind when in
	    ** logfull to avoid background log forces which wreak havoc on
	    ** the recovery logspace reservation algorithms.
	    */
	    stat = LGshow(LG_S_LGSTS, (PTR)&lgd_status, 
			    sizeof(lgd_status), &length, &sys_err);
	    if (stat != OK)
	    {
		uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		    ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
		uleFormat(NULL, E_DM9017_BAD_LOG_SHOW, &sys_err, ULE_LOG, NULL, 
		    (char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 
		    0, LG_S_LGSTS);
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		status = E_DB_ERROR;
		break;
	    }

	    /*
	    ** If logfull, skip the cache flush.
	    */
	    if (lgd_status & LGD_LOGFULL)
	    {
		/*
		** Pause for a moment since the write-behind event will likely
		** be immediately resignaled. We expect that this 5-second
		** wait will return with "timed-out"; if it returns with
		** "interrupted", then the server is being shut down. If it
		** returns with any other return code, something is awry.
		*/
		stat = CSsuspend(CS_TIMEOUT_MASK | CS_INTERRUPT_MASK, 5, 0);
		if (stat == E_CS0008_INTERRUPTED)
		{
		    status = E_DB_OK;
		    break;
		}
		if (stat != E_CS0009_TIMEOUT)
		{
		    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
			ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
		    SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		    status = E_DB_ERROR;
		    break;
		}
	    }
	    else
	    {
		/*
		** Flush some dirty pages out of the Buffer Manager.
		*/

		if (dmf_svcb->svcb_status & SVCB_IOMASTER) 
		{
		    /* in IOMASTER server use same func as write-along thread */
		    i4 numforce;
		    u_i4 duty = 0xffffffff;
		    status = dm0p_write_along(lock_list, (i4)lx_id, 
			    &numforce, duty, dmf_err);
		}
		else
		    status = dm0p_flush_pages(lock_list, (i4)lx_id, 
				    cfa,
				    dmf_err);

		if (status != E_DB_OK)
		{
		    if (dmf_err->err_code > E_DM_INTERNAL)
		    {
			uleFormat(dmf_err, 0, NULL, ULE_LOG, NULL, 
			    (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
			SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		    }
		    break;
		}
	    }

	    /*
	    ** If dumping statistics, save time for event to be signaled.
	    */
	    if (DMZ_ASY_MACRO(2))
		wait_time = TMsecs() - base_time;
	    wbcount++;

	} while (i_am_a_clone == FALSE);
    }

    if (i_am_a_clone == FALSE)
    {
	/* Write Fast Commit thread statistics. */
	stat = CSstatistics(&stat_block, 0);
	TRdisplay("\n%22*- DMF Write Behind Thread statistics %21*-\n");
	TRdisplay("    Write Behind wakeup: %d    Cpu : %d    Dio : %d\n",
	    wbcount, stat_block.stat_cpu, stat_block.stat_dio);
	TRdisplay("%79*-\n");
    }

    /*
    ** Clean up transaction and/or lock list left hanging around.
    */
    if (have_transaction)
    {
	stat = LGend(lx_id, 0, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900E_BAD_LOG_END, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lx_id);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		status = E_DB_ERROR;
	    }
	}
	have_transaction = FALSE;
    }

    if (have_locklist)
    {
	stat = LKrelease(LK_ALL, lock_list, (LK_LKID *)0, (LK_LOCK_KEY *)0,
	    (LK_VALUE *)0, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM901B_BAD_LOCK_RELEASE, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lock_list);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		status = E_DB_ERROR;
	    }
	}
	have_locklist = FALSE;
    }

    if (lg_added)
    {
	stat = LGremove(lg_dbid, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM9016_BAD_LOG_REMOVE, &sys_err, ULE_LOG, NULL, 
		    (char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lg_dbid);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(dmf_err, 0, E_DM0117_WRITE_BEHIND);
		status = E_DB_ERROR;
	    }
	}
    }

    return (status);
}
Beispiel #6
0
/*{
**
** Name: dmc_write_along   -  asynchronous, unobtrusive  write along thread
**
** EXTERNAL call format:	status = dmf_call(DMC_WRITE_ALONG, &dmc_cb);
**
** Description:
**	The dmc_write_along routine provides an unobtrusive version of the  
**	write behind threads found in normal servers.  It's job is similar,
**	writing dirty pages out of the cache to make room for new pages,
**	but the following differences exist:
**        Write Behind threads			Write Along Threads
**	  ---------------------------    -----------------------------------
**	Run as part of same servers	Run in a dedicated IO server so that SMP
**	that process user threads	CPUs are better utilized, and UNIX
**					priorities may be used for balancing
**
**	Runs on any type of UNIX	Will only come up on an SMP machine
**	hardware.			with 2 or more CPUs.
**
**	Contend against user threads 	If there is an available CPU, only
**	from same server, and cause	contention is against other service
**	context switching overhead.	threads in this IO server, eg the
**					new ReadAhead threads.
**
**	Are woken all at once, in a  	Are woken up periodically so that 
**	'panic' when low on buffers, 	I/O is spread out more evenly.
**	causing spikes in processing.
**	
**	All threads in all servers	The I/O master server is given a
**	check all modified buffers, 	list of databases it is to operate on
**	always attempting to 'fix' a   	and keeps them open. When a buffer
**	TBIO and ignoring this buf if	otherwise qualifies to be written, if
**	cant get TBIO. This is alot	the table is not already open (and its
**	of thrashing, eg if the same	one of the desired database) the table
**    	tables happen not to be open	is opened. Thus there is less senseless
**	in all servers.			spinning around the cache.
**
**	The modified queues are   	At the cost of some extra cpu time  	
**    	scanned, which is smart, but	(on the surface), the entire buffer
**    	requires holding the buffer	header array is scanned for candidates.
**    	manager mutex, which is bad !.	This kind of scan can be done without
**    	This causes dead waits.		the buffer manager mutex, so the
**    					scan does not get in the way of other
**    					concurrent operations. The mutex is
**    					taken only when needed to alter the
**    					status of a chosen buffer.
**    	
**    	Because WB threads operate in	Because WA can afford to be more
**    	panic mode, and must write out	picky, only buffers that will not
**    	buffers right away, no regard	cause a log force (old lsns) will be
**    	is given to the fact that a	picked to be written. This will
**    	log force may occur due to a	reduce the amount of log records
**    	new lsn on the buffer.		written, LG mutexes etc...
**    	
**    	
**	The dmc_write_along  routine should only be called within a special
**	session that is dedicated for this purpose.  This routine will not
**	return under normal circumstances until server shutdown time.
**
**	This routines wakes up periodically, and calls dm0p_write_along(),
**	which writes pages in a manner that is less intrusive than the
**	dm0p_flush_pages() routines used by normal write behind threads.
**	dm0p_write_along() will not request or hold the buffer manager
**	mutes while looking for victims, instead it does a sequential
**	scan through the main buffer array. Other differences are listed
**	in the above chart, and in the function header.
**
**	This routine will return only if the timer                          
**	is cancelled by an interrupt.  At server shutdown time, the server
**	is expected to interrupt all such service threads.      
**
** Inputs:
**     dmc_cb
** 	.type		    Must be set to DMC_CONTROL_CB.
** 	.length		    Must be at least sizeof(DMC_CB).
**
** Outputs:
**     dmc_cb
** 	.error.err_code	    One of the following error numbers.
**			    E_DB_OK
**			    E_DM004A_INTERNAL_ERROR
**			    E_DM004B_LOCK_QUOTA_EXCEED
**			    E_DM0062_TRAN_QUOTA_EXCEED
**			    E_DM0163_WRITE_ALONG_FAILURE
**
** Returns:
**     E_DB_OK
**     E_DB_FATAL
**
** History:
**	05-Apr-1995 (cohmi01)
**	    Created, as part of the Manmanx research.
**	10-jan-1996 (dougb)
**	    To get this file to allow links on VMS platform, use CSswitch()
**	    not the internal Unix CL routine CL_swuser().  Also, printf()
**	    should never be called from generic code.
*/
DB_STATUS
dmc_write_along(
DMC_CB	    *dmc_cb)
{
    DMC_CB	    *dmc = dmc_cb;
    DM_SVCB	    *svcb = dmf_svcb;
    DB_TRAN_ID	    tran_id;
    LG_LXID	    lx_id;
    DM0L_ADDDB	    add_info;
    TIMERSTAT	    stat_block;
    i4	    lock_list;
    i4		    len_add_info;
    i4		    event_mask;
    i4		    events, wakeup_event;
    i4		    have_locklist = FALSE;
    i4		    have_transaction = FALSE;
    DB_STATUS	    status = E_DB_OK;
    i4	    wbcount = 0;
    i4	    base_time = 0;
    i4	    flush_time, new_time;
    i4	    length;
    i4	    lgd_status;
#define WA_RUNAGAIN     0     /* indicate no sleep desired */
#define WA_SLEEP        1     /* normal sleep interval if buffers empty */
#define WA_STALL        5     /* sleep interval for log full */
#define WA_YIELD       -1     /* yield to another thread */
    i4	    wa_interval = WA_SLEEP;         
    i4	    numforce = 0;
#define MAX_CLEAN   50
    i4         numclean = 0;
    STATUS	    stat;
    i4	    error;
    CL_ERR_DESC	    sys_err;
    DB_OWN_NAME	    user_name;
    LG_DBID	    lg_dbid;
    static i4  nextwa_threadno = 0;
    i4	    wa_threadno;
    i4	    duties[] = {DM0P_WA_SINGLE | DM0P_WA_GROUPS,
				DM0P_WA_SINGLE,
				DM0P_WA_SINGLE,
                                DM0P_WA_GROUPS};
    i4   	    duty;
#define NUM_DUTY (sizeof(duties)/sizeof (i4))

    CLRDBERR(&dmc->error);

    wa_threadno = nextwa_threadno++;
    duty = duties[wa_threadno % NUM_DUTY];

#ifdef xDEBUG
    TRdisplay(
	"Starting server Write Along Thread for server id 0x%x, duties 0x%x\n",
	      dmc_cb->dmc_id, duty );
#endif

    /*
    ** Add write along  thread to logging system.
    ** Write behind thread does not actually open a database, so use
    ** the LG_NOTDB flag.
    */
    STmove((PTR)DB_BWRITALONG_THREAD, ' ', sizeof(add_info.ad_dbname),
	(PTR) &add_info.ad_dbname);
    MEcopy((PTR)DB_INGRES_NAME, sizeof(add_info.ad_dbowner),
	(PTR) &add_info.ad_dbowner);
    MEcopy((PTR)"None", 4, (PTR) &add_info.ad_root);
    add_info.ad_dbid = 0;
    add_info.ad_l_root = 4;
    len_add_info = sizeof(add_info) - sizeof(add_info.ad_root) + 4;

    stat = LGadd(dmf_svcb->svcb_lctx_ptr->lctx_lgid, LG_NOTDB, (char *)&add_info, 
	len_add_info, &lg_dbid, &sys_err);
    if (stat != OK)
    {
	uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
	    ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	uleFormat(NULL, E_DM900A_BAD_LOG_DBADD, &sys_err, ULE_LOG, NULL,
	    (char *)NULL, 0L, (i4 *)NULL, &error, 4, 0,
	    dmf_svcb->svcb_lctx_ptr->lctx_lgid,
	    sizeof(add_info.ad_dbname), (PTR) &add_info.ad_dbname,
	    sizeof(add_info.ad_dbowner), (PTR) &add_info.ad_dbowner,
	    4, (PTR) &add_info.ad_root);
	if (stat == LG_EXCEED_LIMIT)
	    SETDBERR(&dmc->error, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	else
	    SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
	return (E_DB_ERROR);
    }


    for(;;)
    {
	/*
	** Begin transaction in order to do LG and LK calls.
	** Must specify NOPROTECT transaction so that LG won't pick us
	** as a force-abort victim.  Also, the Log File BOF can be advanced
	** past this transaction's position in the log file, which means that
	** the Write Along thread should do no logging nor work that could
	** require backout.
	*/
	STmove((PTR)DB_BWRITALONG_THREAD, ' ', sizeof(DB_OWN_NAME), 
							(PTR) &user_name);
	stat = LGbegin(LG_NOPROTECT, lg_dbid, &tran_id, &lx_id,
	    sizeof(DB_OWN_NAME), user_name.db_own_name,
	    (DB_DIS_TRAN_ID*)NULL, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900C_BAD_LOG_BEGIN, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 
		0, lg_dbid);
	    if (stat == LG_EXCEED_LIMIT)
		SETDBERR(&dmc->error, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	    else
		SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
	    status = E_DB_ERROR;
	    break;
	}
	have_transaction = TRUE;

	/*
	** Create locklist to use to wait for Write Behind event.
	*/
	stat = LKcreate_list(LK_NONPROTECT, (i4) 0,
	    (LK_UNIQUE *)&tran_id, (LK_LLID *)&lock_list, (i4)0, 
	    &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM901A_BAD_LOCK_CREATE, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    if (stat == LK_NOLOCKS)
		SETDBERR(&dmc->error, 0, E_DM004B_LOCK_QUOTA_EXCEEDED);
	    else
		SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
	    status = E_DB_ERROR;
	    break;
	}
	have_locklist = TRUE;

	/*
	** Now begin timer loop for periodically flushing the buffer manager.
	*/
	for (;;)
	{
	    if (DMZ_ASY_MACRO(2))
	    {
		new_time = TMsecs();
		flush_time = new_time - base_time;
		base_time = new_time;

		/* Write Write Along  thread statistics. */
		stat = CSstatistics(&stat_block, 0);
		TRdisplay("%22*- DMF Write Along Thread statistics %21*-\n");
		TRdisplay("    Write Along wakeups: %d    Cpu : %d    Dio : %d\n",
		    wbcount, stat_block.stat_cpu, stat_block.stat_dio);
		TRdisplay("    Time to flush pages: %d seconds\n",
		    flush_time);
		TRdisplay("%79*-\n");
	    }

	    /*
	    ** Wait for some interval before the next pass over the buffers.
	    ** This should return with "timed-out"; if it returns with
	    ** "interrupted", then the server is being shut down. If it
	    ** returns with any other return code, something is awry.
	    */
	    if (wa_interval == WA_YIELD)
	    {
	        /*
	        ** Note:  This routine will yield only to other threads at
	        ** the same or higher priority.
		*/
		CS_swuser();
	    }
	    else
	    if (wa_interval != WA_RUNAGAIN)
	    {
		stat = CSsuspend(CS_TIMEOUT_MASK | CS_INTERRUPT_MASK, 
			    wa_interval, 0);
		if (stat == E_CS0008_INTERRUPTED)
		{
		    status = E_DB_OK;
		    break;  /* server shut-down */
		}
		if (stat != E_CS0009_TIMEOUT)
		{
		    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
			ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
		    SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
		    status = E_DB_ERROR;
		    break;
		}
	    }
	    
	    /*
	    ** Check LOGFULL status.  We don't execute write behind when in
	    ** logfull to avoid background log forces which wreak havoc on
	    ** the recovery logspace reservation algorithms.
	    */
	    stat = LGshow(LG_S_LGSTS, (PTR)&lgd_status, 
		    sizeof(lgd_status), &length, &sys_err);
	    if (stat != OK)
	    {
		uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		    ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
		uleFormat(NULL, E_DM9017_BAD_LOG_SHOW, &sys_err, ULE_LOG, NULL, 
		    (char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 
		    0, LG_S_LGSTS);
		SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
		status = E_DB_ERROR;
		break;
	    }

	    /*
	    ** If logfull continue back to the top of the loop to bypass
	    ** the cache flush and re-wait for timer  interval.
	    ** Use MAX_WA_INTERVAL to pause while log-full is resolved.
	    */
	    if (lgd_status & LGD_LOGFULL)
	    {
		wa_interval = WA_STALL;        
		continue;   /* bypassing flush during logfull */
	    }

	    wbcount++;
	    
	    /*
	    ** Flush some dirty pages out of the Buffer Manager.
	    */
	    status = dm0p_write_along(lock_list, (i4)lx_id, 
		&numforce, duty, &dmc->error);
	    if (status != E_DB_OK)
	    {
		if (dmc->error.err_code > E_DM_INTERNAL)
		{
		    uleFormat(&dmc->error, 0, NULL, ULE_LOG, NULL, 
			(char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
		    SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
		}
		break;
	    }

	    /* determine next wait period based on how busy we were */
	    /* if we didnt do much, sleep, else ru thru buffers again */
	    if (numforce == 0)
	    {
		wa_interval = WA_SLEEP;  /* things are calm, good nite*/
	    }
	    else
	    {
		wa_interval = WA_RUNAGAIN; /* hit the road again */
	    }

	}

	break;
    }

    /*
    ** Clean up transaction or lock list left hanging around.
    */
    if (have_transaction)
    {
	stat = LGend(lx_id, 0, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900E_BAD_LOG_END, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lx_id);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
		status = E_DB_ERROR;
	    }
	}
	have_transaction = FALSE;
    }
    if (have_locklist)
    {
	stat = LKrelease(LK_ALL, lock_list, (LK_LKID *)0, (LK_LOCK_KEY *)0,
	    (LK_VALUE *)0, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
		ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM901B_BAD_LOCK_RELEASE, &sys_err, ULE_LOG, NULL,
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lock_list);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
		status = E_DB_ERROR;
	    }
	}
	have_locklist = FALSE;
    }

    stat = LGremove(lg_dbid, &sys_err);
    if (stat != OK)
    {
	uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, 
	    ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &error, 0);
	uleFormat(NULL, E_DM9016_BAD_LOG_REMOVE, &sys_err, ULE_LOG, NULL,
	    (char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lg_dbid);
	if ( status == E_DB_OK )
	{
	    SETDBERR(&dmc->error, 0, E_DM0163_WRITE_ALONG_FAILURE);
	    status = E_DB_ERROR;
	}
    }

    /* Write thread statistics. */
    stat = CSstatistics(&stat_block, 0);
    TRdisplay("\n%22*- DMF Write Along Thread statistics %21*-\n");
    TRdisplay("    Write Along wakeup: %d    Cpu : %d    Dio : %d\n",
	wbcount, stat_block.stat_cpu, stat_block.stat_dio);
    TRdisplay("%79*-\n");

    return (status);
}
Beispiel #7
0
/* And now the real thing */
static VOID
opc_exnodearrcnt(
	OPS_STATE	*global,
	QEN_NODE	*node,
	i4		*arrcnts,
	PTR		rowmap)

{
    QEN_OJINFO	*ojinfop;
    QEN_PART_INFO *partp;
    QEN_PART_QUAL *pqual;
    QEN_SJOIN	*sjnp;
    QEN_KJOIN	*kjnp;
    QEN_TJOIN	*tjnp;
    QEN_HJOIN	*hjnp;
    QEN_SEJOIN	*sejnp;
    QEN_SORT	*srtp;
    QEN_TPROC	*tprocp;
    QEN_TSORT	*tsrtp;
    QEN_ORIG	*origp;
    QEN_QP	*qpp;
    QEN_EXCH	*exchp;
    QEF_QP_CB	*qp = global->ops_cstate.opc_qp;
    QEF_RESOURCE *resp;
    QEF_VALID	*vlp;
    QEF_AHD	*act;

    i4		i, j, k;
    i4		dmrix;
    bool	endloop;


    /* Loop (recurse on left, iterate on right) and switch to process
    ** each node in subtree. */

    for ( ; ; )
    {
	if (node == (QEN_NODE *) NULL)
	    return;		/* just in case */

	opc_exnheadcnt(global, node, arrcnts, rowmap);
				/* count node header indexes */

	ojinfop = (QEN_OJINFO *) NULL;
	partp = (QEN_PART_INFO *) NULL;
	pqual = NULL;
	dmrix = -1;

	switch (node->qen_type) {
	  case QE_CPJOIN:
	  case QE_FSMJOIN:
	  case QE_ISJOIN:
	    sjnp = &node->node_qen.qen_sjoin;
	    ojinfop = sjnp->sjn_oj;
	    if (sjnp->sjn_krow >= 0)
		BTset(sjnp->sjn_krow, rowmap);
	    if (sjnp->sjn_hfile >= 0)
		arrcnts[IX_HLD]++;
	    if (sjnp->sjn_itmat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sjnp->sjn_okmat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sjnp->sjn_okcompare != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sjnp->sjn_joinkey != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sjnp->sjn_jqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    opc_exnodearrcnt(global, sjnp->sjn_out, arrcnts, rowmap);
	    node = sjnp->sjn_inner;
	    break;

	  case QE_KJOIN:
	    kjnp = &node->node_qen.qen_kjoin;
	    ojinfop = kjnp->kjoin_oj;
	    partp = kjnp->kjoin_part;
	    pqual = kjnp->kjoin_pqual;
	    if ((dmrix = kjnp->kjoin_get) >= 0)
		arrcnts[IX_DMR]++;
	    if (kjnp->kjoin_krow >= 0)
		BTset(kjnp->kjoin_krow, rowmap);
	    if (kjnp->kjoin_key != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (kjnp->kjoin_kqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (kjnp->kjoin_kcompare != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (kjnp->kjoin_iqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (kjnp->kjoin_jqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    node = kjnp->kjoin_out;
	    break;

	  case QE_TJOIN:
	    tjnp = &node->node_qen.qen_tjoin;
	    ojinfop = tjnp->tjoin_oj;
	    partp = tjnp->tjoin_part;
	    pqual = tjnp->tjoin_pqual;
	    if ((dmrix = tjnp->tjoin_get) >= 0)
		arrcnts[IX_DMR]++;
	    if (tjnp->tjoin_orow >= 0)
		BTset(tjnp->tjoin_orow, rowmap);
	    if (tjnp->tjoin_irow >= 0)
		BTset(tjnp->tjoin_irow, rowmap);
	    if (tjnp->tjoin_jqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (tjnp->tjoin_isnull != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    node = tjnp->tjoin_out;
	    break;

	  case QE_HJOIN:
	    hjnp = &node->node_qen.qen_hjoin;
	    ojinfop = hjnp->hjn_oj;
	    pqual = hjnp->hjn_pqual;
	    arrcnts[IX_HSH]++;
	    if (hjnp->hjn_brow >= 0)
		BTset(hjnp->hjn_brow, rowmap);
	    /* prow is probably already counted as qen_row but make sure */
	    if (hjnp->hjn_prow >= 0)
		BTset(hjnp->hjn_prow, rowmap);
	    if (hjnp->hjn_dmhcb >= 0)
		arrcnts[IX_DMH]++;
	    if (hjnp->hjn_btmat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (hjnp->hjn_ptmat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (hjnp->hjn_jqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    opc_exnodearrcnt(global, hjnp->hjn_out, arrcnts, rowmap);
	    node = hjnp->hjn_inner;
	    break;

	  case QE_SEJOIN:
	    sejnp = &node->node_qen.qen_sejoin;
	    ojinfop = (QEN_OJINFO *) NULL;
	    partp = (QEN_PART_INFO *) NULL;
	    /* if (sejnp->sejn_hget >= 0) - these aren't ref'ed in QEF
		arrcnts[IX_DMR]++; */
	    if (sejnp->sejn_hfile >= 0)
		arrcnts[IX_HLD]++;
	    if (sejnp->sejn_itmat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sejnp->sejn_ccompare != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sejnp->sejn_oqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (sejnp->sejn_okmat != NULL)
		arrcnts[IX_CX]++;
	    if (sejnp->sejn_kcompare != NULL)
		arrcnts[IX_CX]++;
	    if (sejnp->sejn_kqual != NULL)
		arrcnts[IX_CX]++;
	    opc_exnodearrcnt(global, sejnp->sejn_out, arrcnts, rowmap);
	    node = sejnp->sejn_inner;
	    break;

	  case QE_TSORT:
	    tsrtp = &node->node_qen.qen_tsort;
	    pqual = tsrtp->tsort_pqual;
	    if (tsrtp->tsort_get >= 0)
		arrcnts[IX_DMR]++;
	    if (tsrtp->tsort_load >= 0)
		arrcnts[IX_DMR]++;
	    if (tsrtp->tsort_create >= 0)
		arrcnts[IX_DMT]++;
	    if (tsrtp->tsort_shd >= 0)
		arrcnts[IX_SHD]++;
	    if (tsrtp->tsort_mat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    node = tsrtp->tsort_out;
	    break;

	  case QE_SORT:
	    srtp = &node->node_qen.qen_sort;
	    if (srtp->sort_load >= 0)
		arrcnts[IX_DMR]++;
	    if (srtp->sort_create >= 0)
		arrcnts[IX_DMT]++;
	    if (srtp->sort_shd >= 0)
		arrcnts[IX_SHD]++;
	    if (srtp->sort_mat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    node = srtp->sort_out;
	    break;

	  case QE_ORIG:
	  case QE_ORIGAGG:
	    origp = &node->node_qen.qen_orig;
	    if ((dmrix = origp->orig_get) >= 0)
	    {
		arrcnts[IX_DMR]++;
	    }
	    partp = origp->orig_part;
	    pqual = origp->orig_pqual;
	    if (origp->orig_qual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    node = (QEN_NODE *) NULL;
	    break;

	  case QE_QP:
	    qpp = &node->node_qen.qen_qp;
	    if (qpp->qp_qual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    /* Process action headers anchored in QP node. */
	    for (act = node->node_qen.qen_qp.qp_act; act; 
						act = act->ahd_next)
		opc_exactarrcnt(global, act, arrcnts, rowmap);
	    return;

	  case QE_EXCHANGE:
	    exchp = &node->node_qen.qen_exch;
	    if (exchp->exch_mat != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    /* Don't probe below 1:N exchanges, they'll do their own setup.
	    ** 1:1 exchange depends on parent, so keep going.
	    */
	    if (exchp->exch_ccount > 1)
		return;
	    node = exchp->exch_out;
	    break;

	  case QE_TPROC:
	    tprocp = &node->node_qen.qen_tproc;
	    if (tprocp->tproc_parambuild != NULL)
		arrcnts[IX_CX]++;
	    if (tprocp->tproc_qual != NULL)
		arrcnts[IX_CX]++;
	    return;		/* Nothing else interesting */

	  default:
	    TRdisplay("Unexpected QP node type %d under exch\n",node->qen_type);
	    opx_error(E_OP068E_NODE_TYPE);
	}	/* end of switch */

	/* Node specific bits have been set - now go over OJ and
	** partition stuff (if any). */
	if (ojinfop)
	{
	    if (ojinfop->oj_heldTidRow >= 0)
		BTset(ojinfop->oj_heldTidRow, rowmap);
	    if (ojinfop->oj_ijFlagsRow >= 0)
		BTset(ojinfop->oj_ijFlagsRow, rowmap);
	    if (ojinfop->oj_resultEQCrow >= 0)
		BTset(ojinfop->oj_resultEQCrow, rowmap);
	    if (ojinfop->oj_specialEQCrow >= 0)
		BTset(ojinfop->oj_specialEQCrow, rowmap);
	    if (ojinfop->oj_tidHoldFile >= 0)
		arrcnts[IX_HLD]++;
	    if (ojinfop->oj_ijFlagsFile >= 0)
		arrcnts[IX_HLD]++;
	    if (ojinfop->oj_innerJoinedTIDs)
		arrcnts[IX_TTAB]++;
	    if (ojinfop->oj_oqual != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (ojinfop->oj_equal != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (ojinfop->oj_lnull != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	    if (ojinfop->oj_rnull != (QEN_ADF *) NULL)
		arrcnts[IX_CX]++;
	}

	if (partp)
	{
	    if (partp->part_groupmap_ix >= 0)
		BTset(partp->part_groupmap_ix, rowmap);
	    if (partp->part_ktconst_ix >= 0)
		BTset(partp->part_ktconst_ix, rowmap);
	    if (partp->part_knokey_ix >= 0)
		BTset(partp->part_knokey_ix, rowmap);
	}

	/* Part-qual structures contain mini-programs that must be
	** scanned to gather up row numbers.
	*/
	if (pqual != NULL)
	{
	    QEN_PQ_EVAL *pqe;

	    arrcnts[IX_PQUAL]++;
	    if (pqual->part_constmap_ix >= 0)
		BTset(pqual->part_constmap_ix, rowmap);
	    if (pqual->part_lresult_ix >= 0)
		BTset(pqual->part_lresult_ix, rowmap);
	    if (pqual->part_work1_ix >= 0)
		BTset(pqual->part_work1_ix, rowmap);
	    pqe = pqual->part_const_eval;
	    if (pqe != NULL)
		opc_arrcnt_pqe(pqe, arrcnts, rowmap);
	    pqe = pqual->part_join_eval;
	    if (pqe != NULL)
		opc_arrcnt_pqe(pqe, arrcnts, rowmap);
	}

	/* If TJOIN, KJOIN or ORIG, locate DMT_CB index in valid's. */
	if (dmrix >= 0)
	 for (resp = qp->qp_resources, endloop = FALSE; resp && !endloop; 
			resp = resp->qr_next)
	  if (resp->qr_type == QEQR_TABLE)
	   for (vlp = resp->qr_resource.qr_tbl.qr_lastvalid; vlp && !endloop;
			vlp = vlp->vl_next)
	    if (dmrix == vlp->vl_dmr_cb)
	    {
		arrcnts[IX_DMT]++;
		endloop = TRUE;
		if (vlp->vl_partition_cnt > 1)
		    arrcnts[IX_DMR]++;
				/* set master DMR_CB, too */
	    }

	if (node == (QEN_NODE *) NULL)
	    return;
    }	/* end of for ( ; ; ) */

}
Beispiel #8
0
/*{
** Name: CK_subst - build a CK command from template and requirements
**
** Description:
**	This function will search a CK command template file for
**	a line meeting the requirements of the inputs and will substitute
**	various esacpe sequences with other strings such as file names.
**
**	Based on a II_subst of the 5.0 UNIX CL.
**
** Inputs:
**	comlen			length of cline space
**	oper			operation - one of 'B'egin, 'E'nd, 'W'ork
**	dev			device type - one of 'T'ape, 'D'isk
**	dir			direction - one of 'S'ave, 'R'estore
**	type			type (device type) 0 for disk, 1 for tape
**	locnum			location number (sequence or quantity)
**	di_l_path		length of di path string
**	di_path			di path string
**	ckp_l_path		length of checkpoint path string
**	ckp_path		checkpoint path string
**	ckp_l_file		length of checkpoint file string
**	ckp_file		checkpoint file string
**
** Outputs:
**	cline			space for generated command
**
**	Returns:
**	    CK_FILENOTFOUND	template file can't be found
**	    E_DB_OK
**
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**      27-oct-88 (anton)
**	    Created.
**	16-may-90 (walt)
**	    Return CK_FILENOTFOUND if the template file (cktmpl.def) can't
**	    be opened.
**	23-may-1994 (bryanp)
**	    Modified Walt's 16-may-90 fix to use CK_TEMPLATE_MISSING, rather
**		than CK_FILENOTFOUND, since CK_TEMPLATE_MISSING is a more
**		specific, and therefore hopefully more useful, error message.
**	03-jan-1995 (dougb)
**	    Cross-integrate Unix change 415365:
**	    02-dec-1994 (andyw)
**		Check on granularity for partial backup
*/
STATUS
CK_subst(
char	*cline,
i4	comlen,
char	oper, 
char	dev, 
char	dir,
u_i4	type, 
u_i4	locnum, 
u_i4	di_l_path, 
char	*di_path,
u_i4	ckp_l_path, 
char	*ckp_path,
u_i4	ckp_l_file,
char	*ckp_file)
{
    STATUS		ret_val = OK;
    auto LOCATION	loc;
    auto char		*s;
    auto FILE		*fp;
    auto char		*cp;
    char		*command;

    command = MEreqmem(0, comlen, TRUE, &ret_val);

    if (!ret_val)
    {
	NMgtAt("II_CKTMPL_FILE", &s);
	if (s == NULL || *s == EOS)
	{
	    ret_val = NMf_open("r", "cktmpl.def", &fp);
	}
	else
	{
	    LOfroms( PATH & FILENAME, s, &loc );
	    ret_val = SIopen( &loc, "r", &fp);
	}
	if (ret_val)
	{
	    ret_val = CK_TEMPLATE_MISSING;
	}
    }

    /* find command line - skip comments and blank lines */
    if (!ret_val)
    {
	while ((ret_val = SIgetrec(command, comlen, fp)) == OK)
	{
	    if (*command == '\n')
	    {
		continue;
	    }
	    if (command[0] == oper
		&& (command[1] == dir || command[1] == 'E')
		&& (command[2] == dev || command[2] == 'E')
		&& (command[3] == 'D' || command[3] == 'E')
		&& command[4] == ':')
	    {
		break;
	    }
	}
    }

    _VOID_ SIclose(fp);

    if (!ret_val)
    {
	/* found the line - do the substitution */
	s = command + 5;
	cp = cline;
	while (*s != '\n')
	{
	    if (*s == '%')
	    {
		switch (*++s)
		{
		case '%':
		    *cp++ = '%';
		    break;
		case 'D':
		    CK_lfill(&cp, di_l_path, di_path);
		    break;
		case 'C':
		    CK_lfill(&cp, ckp_l_path, ckp_path);
		    break;
		case 'F':
		    CK_lfill(&cp, ckp_l_file, ckp_file);
		    break;
		case 'A':
		    CK_lfill(&cp, ckp_l_path, ckp_path);
# ifdef	UNIX
		    *cp++ = '/';
# endif
		    CK_lfill(&cp, ckp_l_file, ckp_file);
		    break;
		case 'T':
		    *cp++ = type ? '1' : '0';
		    break;
		case 'N':
		    CVna(locnum, cp);
		    while (*cp)
			cp++;
		    break;
		default:
		    *cp++ = '%';
		    *cp++ = *s;
		}
		++s;
	    }
	    else
	    {
		*cp++ = *s++;
	    }
	}
	*cp = EOS;
    }

# ifdef	xDEBUG
    TRdisplay("CK_subst %c %c %c: %s\n", oper, dir, dev, cline);
# endif
    return(ret_val);
}
Beispiel #9
0
/*{
** Name: OPC_EXNODEARRSET	- set DSH ptr array indexes in exch_array1/2
**
** Description: Analyze QP subtree saving DSH ptr array indexes to indicate 
**	the buffers and structures that need to be allocated for child 
**	thread DSH
**
** Inputs:
**
** Outputs:
**	Returns:
**	Exceptions:
**
** Side Effects:
**
** History:
**      1-mar-04 (inkdo01)
**	    Written for || query processing.
**	28-apr-04 (inkdo01)
**	    Forgot to set bits for QEN_STATUS and hash structures.
**	11-june-04 (inkdo01)
**	    Code to recurse on actions owned by QP node.
**	15-june-04 (inkdo01)
**	    Remove sejn_hget from bit map - not used (and not filled in)
**	    in QEF.
**	17-june-04 (inkdo01)
**	    Add logic to set QEN_PQ_RESET to allow earlier thread shutdown.
**	22-july-04 (inkdo01)
**	    Reworked to produce arrays of DSH ptr array indexes.
**	27-aug-04 (inkdo01)
**	    Forgot QEN_PART_INFOs addr'ed from ORIG nodes.
**	10-sep-04 (inkdo01)
**	    Remove QEN_PART_INFO entities from arrays.
**	15-May-2010 (kschendel) b123565
**	    Add missing TPROC case to prevent looping;  add default.
**	    Continue below 1:1 exch, as they depend on parents.
**	    Delete "resettable", done as a separate pass in opcran now.
**	19-May-2010 (kschendel) b123759
**	    ijFlagsFile is a hold, not a row.
**	    Don't need to do rows here, done via bitmap.
*/
static VOID
opc_exnodearrset(
	OPS_STATE	*global,
	QEN_NODE	*node,
	i2		*array1,
	i4		*array2,
	i4		*arrcnts)

{
    QEN_OJINFO	*ojinfop;
    QEN_PART_QUAL *pqual;
    QEN_SJOIN	*sjnp;
    QEN_KJOIN	*kjnp;
    QEN_TJOIN	*tjnp;
    QEN_HJOIN	*hjnp;
    QEN_SEJOIN	*sejnp;
    QEN_SORT	*srtp;
    QEN_TPROC	*tprocp;
    QEN_TSORT	*tsrtp;
    QEN_ORIG	*origp;
    QEN_QP	*qpp;
    QEN_EXCH	*exchp;
    QEF_QP_CB	*qp = global->ops_cstate.opc_qp;
    QEF_RESOURCE *resp;
    QEF_VALID	*vlp;
    QEF_AHD	*act;

    i4		i, j, k;
    i4		dmrix;
    bool	endloop;


    /* Loop (recurse on left, iterate on right) and switch to process
    ** each node in subtree. */

    for ( ; ; )
    {
	if (node == (QEN_NODE *) NULL)
	    return;		/* just in case */

	opc_exnheadset(global, node, array1, array2, arrcnts);
				/* set node header indexes */

	ojinfop = (QEN_OJINFO *) NULL;
	pqual = NULL;
	dmrix = -1;

	switch (node->qen_type) {
	  case QE_CPJOIN:
	  case QE_FSMJOIN:
	  case QE_ISJOIN:
	    sjnp = &node->node_qen.qen_sjoin;
	    ojinfop = sjnp->sjn_oj;
	    if (sjnp->sjn_hfile >= 0)
		array1[arrcnts[IX_HLD]++] = sjnp->sjn_hfile;
	    if (sjnp->sjn_itmat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sjnp->sjn_itmat->qen_pos;
	    if (sjnp->sjn_okmat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sjnp->sjn_okmat->qen_pos;
	    if (sjnp->sjn_okcompare != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sjnp->sjn_okcompare->qen_pos;
	    if (sjnp->sjn_joinkey != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sjnp->sjn_joinkey->qen_pos;
	    if (sjnp->sjn_jqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sjnp->sjn_jqual->qen_pos;
	    opc_exnodearrset(global, sjnp->sjn_out, array1, array2, arrcnts);
	    node = sjnp->sjn_inner;
	    break;

	  case QE_KJOIN:
	    kjnp = &node->node_qen.qen_kjoin;
	    ojinfop = kjnp->kjoin_oj;
	    pqual = kjnp->kjoin_pqual;
	    if ((dmrix = kjnp->kjoin_get) >= 0)
		array2[arrcnts[IX_DMR]++] = kjnp->kjoin_get;
	    if (kjnp->kjoin_key != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = kjnp->kjoin_key->qen_pos;
	    if (kjnp->kjoin_kqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = kjnp->kjoin_kqual->qen_pos;
	    if (kjnp->kjoin_kcompare != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = kjnp->kjoin_kcompare->qen_pos;
	    if (kjnp->kjoin_iqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = kjnp->kjoin_iqual->qen_pos;
	    if (kjnp->kjoin_jqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = kjnp->kjoin_jqual->qen_pos;
	    node = kjnp->kjoin_out;
	    break;

	  case QE_TJOIN:
	    tjnp = &node->node_qen.qen_tjoin;
	    ojinfop = tjnp->tjoin_oj;
	    pqual = tjnp->tjoin_pqual;
	    if ((dmrix = tjnp->tjoin_get) >= 0)
		array2[arrcnts[IX_DMR]++] = tjnp->tjoin_get;
	    if (tjnp->tjoin_jqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = tjnp->tjoin_jqual->qen_pos;
	    if (tjnp->tjoin_isnull != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = tjnp->tjoin_isnull->qen_pos;
	    node = tjnp->tjoin_out;
	    break;

	  case QE_HJOIN:
	    hjnp = &node->node_qen.qen_hjoin;
	    ojinfop = hjnp->hjn_oj;
	    pqual = hjnp->hjn_pqual;
	    array1[arrcnts[IX_HSH]++] = hjnp->hjn_hash;
	    if (hjnp->hjn_dmhcb >= 0)
		array2[arrcnts[IX_DMH]++] = hjnp->hjn_dmhcb;
	    if (hjnp->hjn_btmat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = hjnp->hjn_btmat->qen_pos;
	    if (hjnp->hjn_ptmat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = hjnp->hjn_ptmat->qen_pos;
	    if (hjnp->hjn_jqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = hjnp->hjn_jqual->qen_pos;
	    opc_exnodearrset(global, hjnp->hjn_out, array1, array2, arrcnts);
	    node = hjnp->hjn_inner;
	    break;

	  case QE_SEJOIN:
	    sejnp = &node->node_qen.qen_sejoin;
	    ojinfop = (QEN_OJINFO *) NULL;
	    /* if (sejnp->sejn_hget >= 0) - these aren't ref'ed in QEF
		array2[arrcnts[IX_DMR]++] = sejnp->sejn_hget; */
	    if (sejnp->sejn_hfile >= 0)
		array1[arrcnts[IX_HLD]++] = sejnp->sejn_hfile;
	    if (sejnp->sejn_itmat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_itmat->qen_pos;
	    if (sejnp->sejn_ccompare != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_ccompare->qen_pos;
	    if (sejnp->sejn_oqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_oqual->qen_pos;
	    if (sejnp->sejn_okmat != NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_okmat->qen_pos;
	    if (sejnp->sejn_kcompare != NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_kcompare->qen_pos;
	    if (sejnp->sejn_kqual != NULL)
		array2[arrcnts[IX_CX]++] = sejnp->sejn_kqual->qen_pos;
	    opc_exnodearrset(global, sejnp->sejn_out, array1, array2, arrcnts);
	    node = sejnp->sejn_inner;
	    break;

	  case QE_TSORT:
	    tsrtp = &node->node_qen.qen_tsort;
	    pqual = tsrtp->tsort_pqual;
	    if (tsrtp->tsort_get >= 0)
		array2[arrcnts[IX_DMR]++] = tsrtp->tsort_get;
	    if (tsrtp->tsort_load >= 0)
		array2[arrcnts[IX_DMR]++] = tsrtp->tsort_load;
	    if (tsrtp->tsort_create >= 0)
		array2[arrcnts[IX_DMT]++] = tsrtp->tsort_create;
	    if (tsrtp->tsort_shd >= 0)
		array1[arrcnts[IX_SHD]++] = tsrtp->tsort_shd;
	    if (tsrtp->tsort_mat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = tsrtp->tsort_mat->qen_pos;
	    node = tsrtp->tsort_out;
	    break;

	  case QE_SORT:
	    srtp = &node->node_qen.qen_sort;
	    if (srtp->sort_load >= 0)
		array2[arrcnts[IX_DMR]++] = srtp->sort_load;
	    if (srtp->sort_create >= 0)
		array2[arrcnts[IX_DMT]++] = srtp->sort_create;
	    if (srtp->sort_shd >= 0)
		array1[arrcnts[IX_SHD]++] = srtp->sort_shd;
	    if (srtp->sort_mat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = srtp->sort_mat->qen_pos;
	    node = srtp->sort_out;
	    break;

	  case QE_ORIG:
	  case QE_ORIGAGG:
	    origp = &node->node_qen.qen_orig;
	    pqual = origp->orig_pqual;
	    if ((dmrix = origp->orig_get) >= 0)
	    {
		array2[arrcnts[IX_DMR]++] = origp->orig_get;
	    }
	    if (origp->orig_qual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = origp->orig_qual->qen_pos;
	    node = (QEN_NODE *) NULL;
	    break;

	  case QE_QP:
	    qpp = &node->node_qen.qen_qp;
	    if (qpp->qp_qual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = qpp->qp_qual->qen_pos;
	    /* Process action headers anchored in QP node. */
	    for (act = node->node_qen.qen_qp.qp_act; act; 
						act = act->ahd_next)
		opc_exactarrset(global, act, array1, array2, arrcnts);
	    return;

	  case QE_EXCHANGE:
	    exchp = &node->node_qen.qen_exch;
	    if (exchp->exch_mat != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = exchp->exch_mat->qen_pos;
	    /* Don't probe below 1:N exchanges, they'll do their own setup.
	    ** 1:1 exchange depends on parent, so keep going.
	    */
	    if (exchp->exch_ccount > 1)
		return;
	    node = exchp->exch_out;
	    break;

	  case QE_TPROC:
	    tprocp = &node->node_qen.qen_tproc;
	    if (tprocp->tproc_parambuild != NULL)
		array2[arrcnts[IX_CX]++] = tprocp->tproc_parambuild->qen_pos;
	    if (tprocp->tproc_qual != NULL)
		array2[arrcnts[IX_CX]++] = tprocp->tproc_qual->qen_pos;
	    return;		/* Nothing underneath */

	  default:
	    TRdisplay("Unexpected QP node type %d under exch\n",node->qen_type);
	    opx_error(E_OP068E_NODE_TYPE);
	}	/* end of switch */

	/* Node specific bits have been set - now go over OJ and
	** partition stuff (if any). */
	if (ojinfop)
	{
	    if (ojinfop->oj_tidHoldFile >= 0)
		array1[arrcnts[IX_HLD]++] = ojinfop->oj_tidHoldFile;
	    if (ojinfop->oj_ijFlagsFile >= 0)
		array1[arrcnts[IX_HLD]++] = ojinfop->oj_ijFlagsFile;
	    if (ojinfop->oj_innerJoinedTIDs)
		array1[arrcnts[IX_TTAB]++] = ojinfop->oj_innerJoinedTIDs->
			ttb_tempTableIndex;
	    if (ojinfop->oj_oqual != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = ojinfop->oj_oqual->qen_pos;
	    if (ojinfop->oj_equal != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = ojinfop->oj_equal->qen_pos;
	    if (ojinfop->oj_lnull != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = ojinfop->oj_lnull->qen_pos;
	    if (ojinfop->oj_rnull != (QEN_ADF *) NULL)
		array2[arrcnts[IX_CX]++] = ojinfop->oj_rnull->qen_pos;
	}

	if (pqual != NULL)
	{
	    array1[arrcnts[IX_PQUAL]++] = pqual->part_pqual_ix;
	    if (pqual->part_const_eval != NULL)
		array2[arrcnts[IX_CX]++] = pqual->part_const_eval->un.hdr.pqe_cx->qen_pos;
	    if (pqual->part_join_eval != NULL)
		array2[arrcnts[IX_CX]++] = pqual->part_join_eval->un.hdr.pqe_cx->qen_pos;
	}

	/* If TJOIN, KJOIN or ORIG, locate DMT_CB index in valid's. */
	if (dmrix >= 0)
	 for (resp = qp->qp_resources, endloop = FALSE; resp && !endloop; 
			resp = resp->qr_next)
	  if (resp->qr_type == QEQR_TABLE)
	   for (vlp = resp->qr_resource.qr_tbl.qr_lastvalid; vlp && !endloop;
			vlp = vlp->vl_next)
	    if (dmrix == vlp->vl_dmr_cb)
	    {
		array2[arrcnts[IX_DMT]++] = vlp->vl_dmf_cb;
		endloop = TRUE;
		if (vlp->vl_partition_cnt > 1)
		    array2[arrcnts[IX_DMR]++] = dmrix - 1;
				/* set master DMR_CB, too */
	    }

	if (node == (QEN_NODE *) NULL)
	    return;
    }	/* end of for ( ; ; ) */

}
Beispiel #10
0
/*{
** Name: opx_rverror	- this routine will report another facility's error
**
** Description:
**      This routine will log an error from another facility and the related
**      optimizer error.  
**
** Inputs:
**      opfcb                           ptr to another facility's control block
**      error                           optimizer error code to report
**      facility                        ptr to facility's control block
**
** Outputs:
**	Returns:
**	    VOID
**	Exceptions:
**	    - internal exception generated
**
** Side Effects:
**	    the exception handling routines are responsible for
**          deallocating OPF resources bound to this session.
**
** History:
**	3-jul-86 (seputis)
**          initial creation
**	21-may-89 (jrb)
**	    now passes generic_error to opx_sccerror routine
**	24-oct-92 (andre)
**	    interfaces of ule_format() and opx_sccerror() have been changed to
**	    receive (DB_SQLSTATE *)
**	24-Oct-2008 (jonj)
**	    Replace ule_doformat with ule_format.
[@history_line@]...
*/
VOID
opx_rverror(
	OPF_CB             *opfcb,
	DB_STATUS          status,
	OPX_ERROR          error,
	OPX_FACILITY       facility)
{
    DB_STATUS	    ule_status;		/* return status from ule_format */
    i4         ule_error;          /* ule cannot format message */
    char	    msg_buffer[DB_ERR_SIZE]; /* error message buffer */
    i4         msg_buf_length;     /* length of message returned */
    i4         log;                /* logging state */
    DB_SQLSTATE	    sqlstate;

    opfcb->opf_errorblock.err_code = error;	/* save error code */
    opfcb->opf_errorblock.err_data = facility;	/* save code 
                                                ** from facility */
    if ((error % 256) < 128)
	log = ULE_LOOKUP;		/* lookup only user errors with range
					** of 0-127 */
    else
	log = ULE_LOG;			/* log errors with range 128-255 */

#ifdef    OPT_F031_WARNINGS
    /* if trace flag is set then warning or info errors will be reported */
    if ( DB_SUCCESS_MACRO(status))
    {
	OPS_CB	    *ops_cb;
	ops_cb = ops_getcb();
	if (ops_cb
	    &&
	    (   !ops_cb->ops_check 
		||
		!opt_strace( ops_cb, OPT_F031_WARNINGS)
	    ))
		return;
    }
#endif
    ule_status = ule_format( error, (CL_SYS_ERR *)NULL, log, &sqlstate,
	msg_buffer, (i4) (sizeof(msg_buffer)-1), &msg_buf_length,
	&ule_error, 0);
    if (ule_status != E_DB_OK)
    {
        (VOID)STprintf(msg_buffer, 
"ULE error = %x\nOptimizer cannot be found - error no = %x Status = %x Facility error = %x \n", 
	    ule_error, error , status, facility);
    }
    else
	msg_buffer[msg_buf_length] = 0;	/* null terminate */
    /* FIXME - should check possible return status and generate a severe error
    ** unless it is simple (like cannot find message) */
    {   /* report any errors in the range 0 to 127 to the user */
        DB_STATUS		scf_status;
	if (facility)
	    scf_status = opx_sccerror(E_DB_WARN, &sqlstate, error,
		msg_buffer,(i4)msg_buf_length);	/* generate
					    ** a warning, so that SCC_TRACE is
                                            ** used, this will ensure that
                                            ** SCC_ERROR will be called with
		                            ** the "facility" error code which
                                            ** will be the ingres user code
                                            ** which will be returned to the
                                            ** equel program */
	else
	    scf_status = opx_sccerror(status, &sqlstate, error, msg_buffer,
		(i4)msg_buf_length);
	if (scf_status != E_DB_OK)
	{
	    TRdisplay( 
		"Optimizer error = %x Status = %x Facility error = %x \n", 
                error , status, facility);
	}
    }
    if (!facility)
	return;				    /* if facility error exists then
					    ** report it in the same way */
    ule_status = ule_format( facility,  (CL_SYS_ERR *)NULL, log, &sqlstate,
	msg_buffer, (i4) (sizeof(msg_buffer)-1), &msg_buf_length,
	&ule_error, 0);
    if (ule_status != E_DB_OK)
    {
        (VOID)STprintf(msg_buffer, 
"ULE error = %x\nOptimizer error = %x Status = %x Facility error cannot be found - error no = %x \n", 
	    ule_error, error , status, facility);
    }
    else
	msg_buffer[msg_buf_length] = 0;	/* null terminate */
    {   
        DB_STATUS		scf1_status;
	scf1_status = opx_sccerror(status, &sqlstate, facility, msg_buffer,
	    (i4)msg_buf_length);
	if (scf1_status != E_DB_OK)
	{
	    TRdisplay( 
		"Optimizer error = %x Status = %x Facility error = %x \n", 
                error , status, facility);
	}
    }
}
Beispiel #11
0
/*{
** Name: dmv_unbtree_del - UNDO of a delete key operation.
**
** Description:
**      This function removes a key from a btree index for the recovery of a
**	delete record operation.
**
** Inputs:
**      dmve				Pointer to dmve control block.
**      tabio				Pointer to table io control block
**      page				Pointer to page on which row was insert
**
** Outputs:
**	error				Pointer to Error return area
**	Returns:
**	    E_DB_OK
**	    E_DB_ERROR
**
**	Exceptions:
**	    none
**
** Side Effects:
**	    none
**
** History:
**	14-dec-1992 (rogerk)
**	    Written for 6.5 recovery.
**	18-jan-1992 (rogerk)
**	    Add check in undo routine for case when null page pointer is
**	    passed because undo was found to be not needed.
**	15-mar-1993 (jnash)
**	    Check dmve->dmve_logging to determine if logging required.
**      26-apr-1993 (bryanp)
**          6.5 Cluster support:
**              Replace all uses of DM_LOG_ADDR with LG_LA or LG_LSN.
**	15-apr-1994 (chiku)
**	    Bug56702: return logfull indication.
**	06-may-1996 (thaju02 & nanpr01)
**	    New page format support: change page header references to 
**	    use macros.
**      22-nov-96 (stial01,dilma04)
**          Row Locking Project:
**          Allocate space only if space reclaimed
**      27-feb-97 (stial01)
**          dmv_unbtree_del() allocate parameter TRUE If dm1cxallocate needed
**          Log key in CLR, needed for row locking
**      21-may-1997 (stial01)
**          Added flags arg to dm0p_unmutex call(s).
*/
static DB_STATUS
dmv_unbtree_del(
DMVE_CB             *dmve,
DMP_TABLE_IO	    *tabio,
DMP_PINFO	    *pinfo,
DM_TID		    *bid,
bool                 allocate)
{
    DM0L_BTDEL		*log_rec = (DM0L_BTDEL *)dmve->dmve_log_rec;
    DB_STATUS		status = E_DB_OK;
    DM_LINE_IDX		childkey;
    DM_LINE_IDX		childtid;
    LG_LSN		lsn;
    DM_TID		temptid;
    i4			temppartno;
    i4			page_type = log_rec->btd_pg_type;
    i4			ix_compressed;
    char		*key;
    i4		flags;
    i4		loc_id;
    i4		loc_config_id;
    bool		index_update;
    i4             update_mode;
    i4			local_err;
    i4			*err_code = &dmve->dmve_error.err_code;
    LG_LRI		lri;
    DMPP_PAGE		*page = pinfo->page;

    CLRDBERR(&dmve->dmve_error);

    /*
    ** If there is nothing to recover, just return.
    */
    if (page == NULL)
	return (E_DB_OK);

    key = &log_rec->btd_vbuf[0];

    index_update = ((DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & 
	DMPP_INDEX) != 0);
    ix_compressed = DM1CX_UNCOMPRESSED;
    if (log_rec->btd_cmp_type != TCB_C_NONE)
	ix_compressed = DM1CX_COMPRESSED;

    /*
    ** Get information on the location to which the update is being made.
    */
    loc_id = DM2F_LOCID_MACRO(tabio->tbio_loc_count, 
	(i4) DM1B_VPT_GET_PAGE_PAGE_MACRO(page_type, page));
    loc_config_id = tabio->tbio_location_array[loc_id].loc_config_id;

    /*
    ** Deletes to non-leaf index pages actually effect more than one entry
    ** on the page.  The logged bid describes the entry from which the
    ** TID pointer is deleted.  The key entry is deleted from the previous
    ** position (if there is one).
    */
    if (index_update)
    {
	childtid = log_rec->btd_bid_child;
	childkey = log_rec->btd_bid_child;
    }
    else
    {
	childtid = bid->tid_tid.tid_line;
	childkey = bid->tid_tid.tid_line;
    }

    /* Index pages do not contain partition numbers */
    temppartno = 0;

    if (index_update && (childkey != 0))
    {
	childkey--;
        dm1cxtget(page_type, log_rec->btd_page_size, page, 
		childkey, &temptid, &temppartno); 
    }


    /*
    ** It would be nice to verify that the child position logged (or calculated
    ** by recovery) is the correct spot in the table, but since we have
    ** no attribute or key information to go on, we cannot do key comparisons.
    ** We must trust that the values are correct.
    ** 
    ** We assume here that there is sufficient space on the page.  If not,
    ** then the dm1cx calls below will catch the error.
    ** Since we will have backed out any inserts to this page that may have
    ** occurred after the delete, we should be assured that the the row will
    ** still fit.  If it doesn't, then a fatal recovery error will occur.
    */

    /* 
    ** Mutex the page.  This must be done prior to the log write.
    */
    dmveMutex(dmve, pinfo);

    /*
    ** Check direction of recovery operation:
    **
    **     If this is a normal Undo, then we log the CLR for the operation
    **     and write the LSN of this CLR onto the newly updated page (unless
    **     dmve_logging is turned off - in which case the rollback is not
    **     logged and the page lsn is unchanged).
    **
    **     If the record being processed is itself a CLR, then we are REDOing
    **     an update made during rollback processing.  Updates are not relogged
    **     in redo processing and the LSN is moved forward to the LSN value of
    **     of the original update.
    **
    ** As of release OpenIngres 2.0, we need the key value in CLRs as well,
    ** because of row locking.
    */
    if ((log_rec->btd_header.flags & DM0L_CLR) == 0)
    {
	if (dmve->dmve_logging)
	{
	    flags = (log_rec->btd_header.flags | DM0L_CLR);

	    /* Extract previous page change info */
	    DM1B_VPT_GET_PAGE_LRI_MACRO(log_rec->btd_pg_type, page, &lri);

	    status = dm0l_btdel(dmve->dmve_log_id, flags, 
		&log_rec->btd_tbl_id, 
		tabio->tbio_relid, 0,
		tabio->tbio_relowner, 0,
		log_rec->btd_pg_type, log_rec->btd_page_size,
		log_rec->btd_cmp_type, 
		log_rec->btd_loc_cnt, loc_config_id,
		bid, childkey, &log_rec->btd_tid, log_rec->btd_key_size, key, 
		&log_rec->btd_header.lsn, &lri, log_rec->btd_partno, 
		log_rec->btd_btflags, &dmve->dmve_error);
	    if (status != E_DB_OK)
	    {
		dmveUnMutex(dmve, pinfo);
		/*
		 * Bug56702: return logfull indication.
		 */
		dmve->dmve_logfull = dmve->dmve_error.err_code;

		uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL,
		    (char *)NULL, (i4)0, (i4 *)NULL, &local_err, 0); 

		SETDBERR(&dmve->dmve_error, 0, E_DM9652_UNDO_BTREE_DEL);
		return(E_DB_ERROR);
	    }
	}
    }
    else
    {
	/*
	** If we are processing recovery of an Insert CLR (redo-ing the undo
	** of an insert) then we don't log a CLR but instead save the LSN
	** of the log record we are processing with which to update the
	** page lsn's.
	*/
	DM0L_MAKE_LRI_FROM_LOG_RECORD(&lri, log_rec);
    }

    /* 
    ** Write the LSN, etc, of the delete record onto the page, unless nologging
    */
    if (dmve->dmve_logging)
	DM1B_VPT_SET_PAGE_LRI_MACRO(page_type, page, &lri);

    update_mode = DM1C_DIRECT;
    if ((dmve->dmve_lk_type == LK_ROW || dmve->dmve_lk_type == LK_CROW) ||
	(!index_update && log_rec->btd_pg_type != TCB_PG_V1 &&
	dmve->dmve_lk_type == LK_PAGE && (log_rec->btd_header.flags & DM0L_PHYS_LOCK)))
	update_mode |= DM1C_ROWLK;

    /*
    ** Undo the delete operation.
    */
    for (;;)
    {
	/*
	** Allocate space if necessary
	*/
	if ( allocate == TRUE )
	{
	    status = dm1cxallocate(page_type, log_rec->btd_page_size,
			    page, update_mode, ix_compressed,
			    &dmve->dmve_tran_id, (i4)0, childkey,
			    log_rec->btd_key_size + 
				DM1B_VPT_GET_BT_TIDSZ_MACRO(
					page_type, page));
	    if (status != E_DB_OK)
	    {
		dm1cxlog_error(E_DM93E0_BAD_INDEX_ALLOC, (DMP_RCB *)NULL, page,
			page_type, log_rec->btd_page_size, childkey);
		break;
	    }
	}

	/*
	** Reinsert the key,tid,partition values.
	*/
    /* If leaf overflow look for entry with matching tid */
    /* skip key comparison all the keys on overflow are the same */
    if (DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & DMPP_CHAIN)
    {
	i4 i;
	DM_TID	tmptid;
	i4	tmppart;
	LG_LSN lsn;
	for (i = 0; i < DM1B_VPT_GET_BT_KIDS_MACRO(page_type, page); i++)
	{
	    dm1cxtget(page_type, log_rec->btd_page_size, page, i, &tmptid, &tmppart); 
	lsn = DMPP_VPT_GET_PAGE_LSN_MACRO(page_type, page);
	    if (log_rec->btd_tid.tid_i4 == tmptid.tid_i4 &&
		dmpp_vpt_test_free_macro(page_type,
		DM1B_VPT_BT_SEQUENCE_MACRO(page_type, page), 
		(i4)i + DM1B_OFFSEQ) == FALSE)
	    TRdisplay("dmvebtdl: dup entry on overflow %d for tid %d,%d CRPAGE %d page lsn %x\n",
		DM1B_VPT_GET_PAGE_PAGE_MACRO(page_type, page),
		log_rec->btd_tid.tid_tid.tid_page,
		log_rec->btd_tid.tid_tid.tid_line,
	        DMPP_VPT_IS_CR_PAGE(page_type, page), lsn.lsn_low);
/*
does this trigger the dm1bxreserve failure from dm1bxovfl_alloc 
	    return (E_DB_ERROR);
*/
	}
    }
	status = dm1cxput(page_type, log_rec->btd_page_size, page,
			ix_compressed, update_mode, 
			&dmve->dmve_tran_id,
			LOG_ID_ID(dmve->dmve_log_id),
			(i4)0, childkey, 
			key, log_rec->btd_key_size, &log_rec->btd_tid,
			log_rec->btd_partno);
	if (status != E_DB_OK)
	{
	    dm1cxlog_error(E_DM93E4_BAD_INDEX_PUT, (DMP_RCB *)NULL, page,
			page_type, log_rec->btd_page_size, childkey);
	    break;
	}

	/*
	** If the insert is to a non-leaf index page, then the logged tid
	** value must actually be insert to the position after the one
	** to which we just put the key.  Replace the old tidp from that
	** position and insert the new one to the next entry.
	*/
	if (index_update && (childkey != childtid))
	{
	    status = dm1cxtput(page_type, log_rec->btd_page_size, 
				page, childtid, &log_rec->btd_tid,
				log_rec->btd_partno);
	    if (status != E_DB_OK)
	    {
		dm1cxlog_error(E_DM93EB_BAD_INDEX_TPUT, (DMP_RCB *)NULL, page,
			page_type, log_rec->btd_page_size, childtid);
		break;
	    }
	    status = dm1cxtput(page_type, log_rec->btd_page_size, 
			page, childkey, &temptid, temppartno);
	    if (status != E_DB_OK)
	    {
		dm1cxlog_error(E_DM93EB_BAD_INDEX_TPUT, (DMP_RCB *)NULL, page,
			page_type, log_rec->btd_page_size, childkey);
		break;
	    }
	}

	break;
    }

    DM1B_VPT_SET_PAGE_STAT_MACRO(page_type, page, DMPP_MODIFY);
    dmveUnMutex(dmve, pinfo);
    
    if (status != E_DB_OK)
    {
	SETDBERR(&dmve->dmve_error, 0, E_DM9652_UNDO_BTREE_DEL);
	return(E_DB_ERROR);
    }

    return(E_DB_OK);
}
Beispiel #12
0
/*{
** Name: DI_slave_read -  Request a slave to read page(s) from a file on disk.
**
** Description:
**	This routine was created to make DIread more readable once
**	error checking had been added. See DIread for comments.
**
** Inputs:
**      f                    Pointer to the DI file
**                           context needed to do I/O.
**	diop		     Pointer to dilru file context.
**      buf                  Pointer to page(s) to read.
**      page                 Value indicating page(s) to read.
**	num_of_pages	     number of pages to read.
**      
** Outputs:
**      err_code             Pointer to a variable used
**                           to return operating system 
**                           errors.
**    Returns:
**          OK
**	    other errors.
**    Exceptions:
**        none
**
** Side Effects:
**        none
**
** History:
**    30-nov-1992 (rmuth)
**	    Created.
**      10-mar-1993 (mikem)
**          Changed the type of the first parameter to DI_send_ev_to_slave() and
**          the 2nd parameter to DI_slave_send(), so that DI_send_ev_to_slave()
**          could access the slave control block's status.
**          This routine will now initialize the status to DI_INPROGRESS, before
**          making the request and the slave will change the status once the
**          operation is complete.
**	23-aug-1993 (bryanp)
**	    If memory segment isn't yet mapped, map it.
*/
static STATUS
DI_slave_read(
    DI_IO	*f,
    DI_OP	*diop,
    char        *buf,
    i4	page,
    i4	num_of_pages,
    i4	*n,
    CL_ERR_DESC *err_code)
{
    register DI_SLAVE_CB        *disl;
    ME_SEG_INFO                 *seginfo;
    bool                        direct_read;
    STATUS			small_status = OK, big_status = OK, 
				intern_status = OK, status;
    
    /* unix variables */
    int		bytes_to_read;
    int		bytes_read = 0;

    do
    {
	disl = diop->di_evcb;
	    
	disl->pre_seek = 
	    (OFFSET_TYPE)(f->io_bytes_per_page) * (OFFSET_TYPE)(page);
	bytes_to_read	= f->io_bytes_per_page * num_of_pages;
	    
	/*
	** determine whether we're reading into shared memory, and set
	** up the segment ID and offset correctly
	*/
	seginfo = ME_find_seg( buf, (char *)buf + bytes_to_read,
	   		       &ME_segpool);

	if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) == 0)
	{
	    status = DI_lru_slmapmem(seginfo, &intern_status, &small_status);
	    if (status)
		break;
	}
	
	if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) != 0)
	{
	    MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key),
		    (PTR)disl->seg_key);

	    disl->seg_offset = (char *)buf - (char *)seginfo->addr;
	    direct_read = TRUE;
	}
	else
	{
	    direct_read = FALSE;
	    seginfo = ME_find_seg(disl->buf, disl->buf, &ME_segpool);
	    if (seginfo)
	    {
		MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key),
		        (PTR)disl->seg_key);

		disl->seg_offset= (char *)disl->buf - (char *)seginfo->addr;
	    }
	    else
	    {
		small_status = DI_BADREAD;
		break;
	    }
	}


	/* 
	** seek to place to read 
	*/
	do 
	{
	    disl->file_op = DI_SL_READ;

	    /* Send file properties to slave */
	    FPROP_COPY(f->io_fprop,disl->io_fprop);
	    
	    if (direct_read)
		disl->length = bytes_to_read;
	    else
		disl->length = min(bytes_to_read, Cs_srv_block.cs_size_io_buf);

	    DI_slave_send( disl->dest_slave_no, diop,
			   &big_status, &small_status, &intern_status);
	    if (( big_status != OK ) || ( small_status != OK ))
		break;

	    if ((small_status = disl->status) != OK ) 
	    {
		STRUCT_ASSIGN_MACRO(disl->errcode, *err_code);
		small_status = DI_BADREAD;
		break;
	    }
	    else
	    {
		if ( disl->length == 0 )
		{
		    small_status = DI_ENDFILE;
#ifdef	xDEV_TST

		    TRdisplay("num_pages %d\n, read_op = %x", 
				  num_of_pages, 0x70000000);
		    DIlru_dump();
#endif	/* xDev_TST */
		    break;

		}
	    }

	    /*
	    ** Read data ok 
	    */
	    if (! direct_read)
	    {
		MEcopy((PTR)disl->buf, disl->length, (PTR)buf);
		buf += disl->length;
	    }

	    bytes_to_read -= disl->length;
	    disl->pre_seek += (OFFSET_TYPE)disl->length;
	    bytes_read	   += disl->length;

	} while ( bytes_to_read > 0);
    } while (FALSE);

    if ( bytes_read > 0 )
	*n = bytes_read / f->io_bytes_per_page;

    if ( big_status != OK )
	small_status = big_status;

    if (small_status != OK )
	DIlru_set_di_error( &small_status, err_code, intern_status,
			    DI_GENERAL_ERR);

    return(small_status);
  }
Beispiel #13
0
/*{
**
** Name: dmc_logwriter	-- Performs I/O to the transaction logfile
**
** EXTERNAL call format:	status = dmf_call(DMC_LOGWRITER, &dmc_cb);
**
** Description:
**	This thread writes log blocks to the log file.
**
**	If all goes well, this routine will not return under normal
**	circumstances until server shutdown time.
**
** Inputs:
**     dmc_cb
** 	.type		    Must be set to DMC_CONTROL_CB.
** 	.length		    Must be at least sizeof(DMC_CB).
**
** Outputs:
**     dmc_cb
** 	.error.err_code	    One of the following error numbers.
**			    E_DB_OK
**			    E_DM004A_INTERNAL_ERROR
**
** Returns:
**     E_DB_OK
**     E_DB_FATAL
**
** History:
**	Summer, 1992 (bryanp)
**	    Working on the new portable logging and locking system
**	3-nov-1992 (bryanp)
**	    We don't need a lock list, so don't create one.
**	10-oct-93 (swm)
**	    Bug #56438
**	    Put LG_DBID into autmatic variable lg_dbid rather than overloading
**	    dmc_cb->dmc_db_id.
**      27-Jul-1998 (horda03)
**          When an error is detected, do not use error_code to store the status
**          of the ule_format() call. This variable contains the error code to be
**          returned to the calling function. (Bug 92183)
*/
DB_STATUS
dmc_logwriter(DMC_CB	    *dmc_cb)
{
    DMC_CB	    *dmc = dmc_cb;
    DM_SVCB	    *svcb = dmf_svcb;
    i4	    	    error_code;
    DB_STATUS	    status = E_DB_OK;
    STATUS	    cl_status;
    CL_ERR_DESC	    sys_err;
    DB_TRAN_ID	    tran_id;
    LG_LXID	    lx_id;
    DM0L_ADDDB	    add_info;
    i4		    len_add_info;
    i4		    have_transaction = FALSE;
    STATUS	    stat;
    i4	    error;
    DB_OWN_NAME	    user_name;
    LG_DBID	    lg_dbid;

#ifdef xDEBUG
    TRdisplay("Starting server Logwriter Thread for server id 0x%x\n",
	dmc->dmc_id);
#endif

    CLRDBERR(&dmc->error);

    STmove((PTR)DB_LOGFILEIO_THREAD, ' ', sizeof(add_info.ad_dbname),
	(PTR) &add_info.ad_dbname);
    MEcopy((PTR)DB_INGRES_NAME, sizeof(add_info.ad_dbowner),
	(PTR) &add_info.ad_dbowner);
    MEcopy((PTR)"None", 4, (PTR) &add_info.ad_root);
    add_info.ad_dbid = 0;
    add_info.ad_l_root = 4;
    len_add_info = sizeof(add_info) - sizeof(add_info.ad_root) + 4;

    stat = LGadd(dmf_svcb->svcb_lctx_ptr->lctx_lgid, LG_NOTDB, (char *)&add_info,
		    len_add_info, &lg_dbid, &sys_err);
    if (stat != OK)
    {
	uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, ULE_LOG, NULL,
			(char *)NULL, 0L, (i4 *)NULL, &error, 0);
	uleFormat(NULL, E_DM900A_BAD_LOG_DBADD, &sys_err, ULE_LOG, NULL,
	    (char *)NULL, 0L, (i4 *)NULL, &error, 4, 0,
	    dmf_svcb->svcb_lctx_ptr->lctx_lgid,
	    sizeof(add_info.ad_dbname), (PTR) &add_info.ad_dbname,
	    sizeof(add_info.ad_dbowner), (PTR) &add_info.ad_dbowner,
	    4, (PTR) &add_info.ad_root);
	if (stat == LG_EXCEED_LIMIT)
	    SETDBERR(&dmc->error, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	else
	    SETDBERR(&dmc->error, 0, E_DM014D_LOGWRITER);
	return (E_DB_ERROR);
    }

    for (;;)
    {
	STmove((PTR)DB_LOGFILEIO_THROWN, ' ', sizeof(DB_OWN_NAME),
		(PTR) &user_name);
	stat = LGbegin(LG_NOPROTECT | LG_LOGWRITER_THREAD,
			lg_dbid, &tran_id, &lx_id, sizeof(DB_OWN_NAME),
			&user_name.db_own_name[0], 
			(DB_DIS_TRAN_ID*)NULL, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, ULE_LOG, NULL,
			(char *)NULL, 0L, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900C_BAD_LOG_BEGIN, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lg_dbid);
	    if (stat == LG_EXCEED_LIMIT)
		SETDBERR(&dmc->error, 0, E_DM0062_TRAN_QUOTA_EXCEEDED);
	    else
		SETDBERR(&dmc->error, 0, E_DM014D_LOGWRITER);
	    status = E_DB_ERROR;
	    break;
	}
	have_transaction = TRUE;

	break;
    }

    for (;status == E_DB_OK;)
    {

	/*
	** The logwriter thread is awakened when a log block needs to be
	** written. It then calls LG_write_block() to write the block out.
	** Then it goes back to sleep until the next log block needs to be
	** written out.
	*/
	cl_status = LG_write_block(lx_id, &sys_err);

	if (cl_status)
	{
	    TRdisplay("Logwriter thread: error %x from LG_write_block.\n",
			cl_status);
	    /*
	    ** Something is fatally wrong in the CL.
	    */
	    uleFormat(NULL, cl_status, (CL_ERR_DESC *)&sys_err, ULE_LOG, NULL,
			(char *)NULL, 0L, (i4 *)NULL, &error, 0);
	    SETDBERR(&dmc->error, 0, E_DM014D_LOGWRITER);
	    status = E_DB_ERROR;
	    break;
	}

	/*
	** Wait for next buffer to write:
	*/
	cl_status = CSsuspend(CS_INTERRUPT_MASK, 0, 0);

	if (cl_status == E_CS0008_INTERRUPTED)
	{
	    /*
	    ** Special threads are interrupted when they should shut down.
	    */

	    /* display a message? */
	    TRdisplay("Logwriter Thread was interrupted; terminating...\n");
	    status = E_DB_OK;
	    break;
	}

	/*
	** loop back around and wait for the next time to write a block:
	*/
    }
    /*
    ** Clean up transaction or lock list left hanging around.
    */
    if (have_transaction)
    {
	stat = LGend(lx_id, 0, &sys_err);
	if (stat != OK)
	{
	    uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, ULE_LOG, NULL,
			(char *)NULL, 0L, (i4 *)NULL, &error, 0);
	    uleFormat(NULL, E_DM900E_BAD_LOG_END, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lx_id);
	    if ( status == E_DB_OK )
	    {
		SETDBERR(&dmc->error, 0, E_DM014D_LOGWRITER);
		status = E_DB_ERROR;
	    }
	}
    }

    stat = LGremove(lg_dbid, &sys_err);
    if (stat != OK)
    {
	uleFormat(NULL, stat, (CL_ERR_DESC *)&sys_err, ULE_LOG, NULL,
			(char *)NULL, 0L, (i4 *)NULL, &error, 0);
	uleFormat(NULL, E_DM9016_BAD_LOG_REMOVE, &sys_err, ULE_LOG, NULL, 
		(char *)NULL, (i4)0, (i4 *)NULL, &error, 1, 0, lg_dbid);
	if ( status == E_DB_OK )
	{
	    SETDBERR(&dmc->error, 0, E_DM014D_LOGWRITER);
	    status = E_DB_ERROR;
	}
    }

    return (status);
}