Пример #1
0
/*
** Name: CS_ef_wait - wait for specified event to occur.
**
** Description:
**	This routine suspends the current thread until a specified event
**	occurs.  The event must have been set using the CS_ef_set call before
**	the thread can call CS_ef_wait.  The event must be signaled by some
**	other thread calling CS_ef_wake with the same event flag.
**
**	The routines that drive the event mechanisms are:
**
**	    CS_ef_set	: set event wait flag for current session
**	    CS_ef_wait	: suspend current session until event is signalled
**	    CS_ef_wake	: signal event - wake up sessions waiting for event
**	    CS_ef_cancel: cancel current session's event wait flag
**
**	After calling CS_ef_set, the client must call either CS_ef_wait or
**	CS_ef_cancel.  Failing to do this will cause the system to get its
**	suspends and resumes out of sync.
**
**	The client of the event routines must be careful of the case where
**	the event desired occurs BEFORE the call to CS_ef_set.  If this
**	case cannot be handled by the client, then the calls to the event
**	routines should be protected by some sort of semaphore, as shown below.
**
**	The CS event routines are not intended to be high traffic - ultra fast
**	event drivers, they are used primarily to wait for out-of-resource
**	conditions to be resolved - these are not expected to happen very often.**
**	Event flag values should be reserved in CS.H.
**	Event waits are NOT interruptable.
**
**	The protocols for using the CS event wait calls are described above
**	in the module header.
**
** Inputs:
**      none
**
** Outputs:
**      none
**
**	Returns:
**	    none
**
**	Exceptions:
**	    none
**
** Side Effects:
**	Thread is suspended until event is signalled by another session.
**
** History:
**      24-jul-89 (rogerk)
**          Created.
*/
VOID
CS_ef_wait()
{
    CS_SCB	*scb;

    CSget_scb(&scb);
    CSsuspend(0, 0, 0);
}
Пример #2
0
/*
** Name: ascs_tracelog - trace log writer
**
** Description:
**      Periodically flushes the trace buffers to disk.
**
**
** Inputs:
**      scb                     session control block
**
** Outputs:
**      None.
**
** Returns:
**      DB_STATUS
**
** History:
**      04-Feb-1999 (fanra01)
**          Created.
*/
static DB_STATUS
ascs_tracelog( SCD_SCB *scb )
{
    DB_STATUS   status = E_DB_OK;
    STATUS	cl_status;

    asct_session_set (scb->cs_scb.cs_self);

    asct_trace (ASCT_LOG)(ASCT_TRACE_PARAMS, "Trace started ....");

    for (;;)
    {

	MEcopy( "Waiting for next check time", 27,
	        scb->scb_sscb.sscb_ics.ics_act1 );
	scb->scb_sscb.sscb_ics.ics_l_act1 = 27;

	/* 
	*/
	cl_status = CSsuspend(CS_INTERRUPT_MASK|CS_TIMEOUT_MASK, 
			asctlogtimeout, NULL);

	if ( cl_status == E_CS0008_INTERRUPTED )
	    break;

	/* expected results are ok, timeout and interrupt only */
        /* ok from resume on thread */
	if ( cl_status != OK && cl_status != E_CS0009_TIMEOUT )
	{
	    status = cl_status;
	    break;
	}

	/* call the check, but don't exit the server on violation */
        if (Sc_main_cb->sc_capabilities & SC_ICE_SERVER)
        {
            DB_ERROR dberr;

            status = asct_flush(&dberr, ASCT_POLLED_FLUSH);
            if (status != E_DB_OK)
            {
                sc0e_0_put(dberr.err_code, 0);
            }
        }
    }

    asct_terminate ();

    if (status != E_DB_OK)
	sc0e_0_put(E_SC0387_LOGTRC_THREAD_EXIT, 0);

    return (status);

}
Пример #3
0
/*
** Name: ascs_periodic_clean - check ICE cleanup
**
** Description:
**      The periodic cleanup thread checks the sessions in the ice server
**      and disconnects timedout ones.
**
** Inputs:
**      scb                     session control block
**
** Outputs:
**      None.
**
** Returns:
**      DB_STATUS
**
** History:
**      04-Feb-1999 (fanra01)
**          Created.
*/
static DB_STATUS
ascs_periodic_clean( SCD_SCB *scb )
{
    DB_STATUS   status = E_DB_OK;
    STATUS	cl_status;

    for (;;)
    {

	MEcopy( "Waiting for next check time", 27,
	        scb->scb_sscb.sscb_ics.ics_act1 );
	scb->scb_sscb.sscb_ics.ics_l_act1 = 27;

	/* 
	** license API states license must be checked at least 
	** 60 times per minute and at most 240 times per minute
	*/
	cl_status = CSsuspend(CS_INTERRUPT_MASK|CS_TIMEOUT_MASK, 
			30, NULL);

	if ( cl_status == E_CS0008_INTERRUPTED )
	    break;

	/* expected results are timeout and interrupt only */
	if ( cl_status != E_CS0009_TIMEOUT )
	{
	    status = cl_status;
	    break;
	}

	/* call the check, but don't exit the server on violation */
        if (Sc_main_cb->sc_capabilities & SC_ICE_SERVER)
        {
            DB_ERROR dberr;

            status = WTSCleanup(&dberr);
            if (status != E_DB_OK)
            {
                sc0e_0_put(dberr.err_code, 0);
            }
        }
    }

    if (status != E_DB_OK)
	sc0e_0_put(E_SC0385_CLEANUP_THREAD_EXIT, 0);

    return (status);

}
Пример #4
0
/*{
** Name: DI_send_ev_to_slave - Send an event to a sepecfied slave
**
** Description:
**
** Inputs:
**	di_op		Event control block.
**	slave_number	Slave who we want to send event to.
**
** Outputs:
**	intern_status	Internal error indicating reason for failure.
**
**    Returns:
**        OK
**	  A range of DIlru errors .
**
**    Exceptions:
**        none
**
** Side Effects:
**
** History:
**    30-nov-1992 (rmuth)
** 	    Created.
**      10-mar-1993 (mikem)
**          bug #47624
**          Bug 47624 resulted in CSsuspend()'s from the DI system being woken
**          up early.  Mainline DI would then procede while the slave would
**          actually be processing the requested asynchronous action.  Various
**          bad things could happen after this depending on timing: (mainline
**          DI would change the slave control block before slave read it,
**          mainline DI would call DIlru_release() and ignore it failing which
**          would cause the control block to never be freed eventually leading
**          to the server hanging when it ran out of slave control blocks, ...
**
**          Fixes were made to scf to hopefully eliminate the unwanted
**          CSresume()'s.  In addition defensive code has been added to DI
**          to catch cases of returning from CSresume while the slave is
**          operating.  Before causing a slave to take action the master will
**          set the slave control block status to DI_INPROGRESS, the slave in
**          turn will not change this status until it has completed the
**          operation.
**
**	    Changed first argument to be a DI_OP pointer so that we could set
**	    disl->status in this one place rather than in all the callers.
**	16-Nov-1998 (jenjo02)
**	    Distinguish between Log I/O, Disk I/O, Read or Write,
**	    when suspended waiting for slave.
**
*/
STATUS
DI_send_ev_to_slave(
    DI_OP     	*di_op,
    i4		slave_number,
    STATUS	*intern_status )
{
    STATUS	status;

    di_op->di_evcb->status = DI_INPROGRESS;
    status = CScause_event(di_op->di_csevcb, slave_number);
    if ( status != OK )
    {
        *intern_status = DI_LRU_CSCAUSE_EV_ERR;
    }
    else
    {
        i4	suspend_mask;

        if (di_op->di_evcb->file_op == DI_SL_WRITE)
            suspend_mask = CS_IOW_MASK;
        else
            suspend_mask = CS_IOR_MASK;

        if (di_op->di_evcb->io_open_flags & DI_O_LOG_FILE_MASK)
            suspend_mask |= CS_LIO_MASK;
        else
            suspend_mask |= CS_DIO_MASK;

        status = CSsuspend( suspend_mask, 0, (PTR)di_op->di_csevcb );
        if ( status != OK )
        {
            *intern_status = DI_LRU_CSSUSPEND_ERR;
        }
    }

    return(status);
}
Пример #5
0
/*{
** Name: GM_gcmsend	- make GCa_call for GCM request.
**
** Description:
**	Makes the call...
**
** Re-entrancy:
**	yes.
**
** Inputs:
**	conn		the connect block with the prepared message to send.
**
** Outputs:
**	conn
**
** Returns:
**	E_DB_OK
**	E_DB_ERROR
**
** History:
**	8-oct-92 (daveb)
**	    created.
**	12-Nov-1992 (daveb)
**	    Need GCA_ALT_EXIT for our completiong routien to be seen.
**	    Add fs_parms var to simplify debugging.
**	14-Nov-1992 (daveb)
**	    take *cl_stat to fill in.
**	20-Nov-1992 (daveb)
**	    Put in more TRdisplay error logging, to fix later.
**	2-Dec-1992 (daveb)
**	    Check for server failed in quick abort case.  Trying to avoid
**	    lots of errors re-connectiong to non-gcm servers.
**	08-sep-93 (swm)
**	    Changed sid type from i4 to CS_SID to match recent CL
**	    interface revision.
**	20-jul-95 (canor01)
**	    pass the SCB to IIGCa_call() instead of the SID
*/
static DB_STATUS
GM_gcmsend( GM_CONN_BLK *conn, STATUS *cl_stat )
{
    DB_STATUS	db_stat;
    CS_SID	sid;
    i4		resume = 0;
    STATUS	local_status;
    GCA_FS_PARMS	*fs_parms = &conn->conn_fs_parms;
    GM_PLACE_BLK	*place = conn->conn_place;

    conn->conn_state = GM_CONN_GCM_WORKING;
    CSget_sid(&sid);
    
    GM_incr( &GM_globals.gwm_stat_sem, &GM_globals.gwm_gcm_sends );

    if( place->place_type == GM_PLACE_SRVR &&
       ((place->place_srvr.srvr_flags & GCA_RG_MIB_MASK) == 0 ||
       place->place_srvr.srvr_state == GM_SRVR_FAILED ))
    {
	/* nothing can be had from this server.  We did a lot of
	   setup work for nothing. FIXME -- move this test higher up? */

	conn->conn_rsb->response.err_element = 0;
	conn->conn_rsb->response.status = *cl_stat = MO_NO_INSTANCE;
	conn->conn_state = GM_CONN_EMPTIED;
	return( E_DB_ERROR );
    }

    do
    {
	*cl_stat = IIGCa_call(GCA_FASTSELECT,
			      (GCA_PARMLIST *)fs_parms,
			      GCA_ASYNC_FLAG | GCA_ALT_EXIT | resume,
			      (PTR)CS_find_scb(sid),
			      (i4) -1,
			      &local_status );
	
	if (*cl_stat != OK)
	{
	    /* "GWM Internal error:  Error making gcm send to %0c" */
	    GM_1error( (GWX_RCB *)0, E_GW8042_GCA_CALL, GM_ERR_INTERNAL,
		      0, (PTR)conn->conn_rsb->request.place );
	    GM_error( *cl_stat );
	    conn->conn_state = GM_CONN_ERROR;
	}
	else
	{
	    /* wait for completion routine to wake us */

	    *cl_stat = CSsuspend(CS_BIO_MASK, 0, 0);
	    if (*cl_stat != OK)
	    {
		/* "GWM Internal error:  CSsuspend problem" */
		GM_error( E_GW8043_CS_SUSPEND );
		GM_error( *cl_stat );
		conn->conn_state = GM_CONN_ERROR;
	    }
	    else		/* completion handler called */
	    {
		switch ( *cl_stat = conn->conn_fs_parms.gca_status )
		{
		case OK:

		    resume = 0;
		    conn->conn_state = GM_CONN_GCM_DONE;
		    break;
		    
		case E_GCFFFE_INCOMPLETE:

		    GM_incr( &GM_globals.gwm_stat_sem,
			    &GM_globals.gwm_gcm_reissues );
		    resume = GCA_RESUME;
		    break;

		case E_GC0032_NO_PEER:

		    resume = 0;

		    /* "GWM Internal error:  Got 'no peer' to %0c (%1c %2x)" */
		    GM_3error( (GWX_RCB *)0, E_GW8044_NO_PEER,
			      GM_ERR_INTERNAL,
			      0, place->place_key,
			      0, place->place_srvr.srvr_class,
			      sizeof(place->place_srvr.srvr_flags),
			      (PTR)&place->place_srvr.srvr_flags );
		    GM_error( *cl_stat );
		    conn->conn_state = GM_CONN_ERROR;
		    break;

		default:

		    resume = 0;

		    /* "GWM Internal error:
		       GCM completion error to %0c (%1c %2x)" */
		    GM_3error( (GWX_RCB *)0, E_GW8045_GCA_COMPLETION,
			      GM_ERR_INTERNAL,
			      0, (PTR)place->place_key,
			      0, (PTR)place->place_srvr.srvr_class,
			      sizeof(place->place_srvr.srvr_flags),
			      (PTR)&place->place_srvr.srvr_flags );
		    GM_error( *cl_stat );
		    conn->conn_state = GM_CONN_ERROR;
		    place->place_srvr.srvr_state = GM_SRVR_FAILED;
		    break;
		}
	    }
	}
    } while( resume != 0 );
    
    db_stat = (*cl_stat == OK) ? E_DB_OK : E_DB_ERROR;

    return( db_stat );
}
Пример #6
0
static STATUS
DI_force(
    DI_IO	*f,
    DI_OP	*diop,
    CL_ERR_DESC	*err_code)
{

    STATUS	big_status = OK, small_status = OK, intern_status = OK;
    register DI_SLAVE_CB	*disl;

    do
    {
        if (Di_slave)
	{
	    disl = diop->di_evcb;
	    disl->file_op = DI_SL_SYNC;
	    /* Send file properties to slave */
	    FPROP_COPY(f->io_fprop,disl->io_fprop);

	    DI_slave_send( disl->dest_slave_no, diop,
			   &big_status, &small_status, &intern_status);

	    if (big_status != OK )
	        break;

	    if ( small_status == OK )
	    {
	        if ((small_status = disl->status) != OK )
	        {
		    STRUCT_ASSIGN_MACRO(disl->errcode, *err_code);
		}
	    }
	}
	else
	{
	    /* 
	    ** put code in here for fsync issues 
	    */
#ifdef xCL_ASYNC_IO
            if( Di_async_io)
	    {
                DI_AIOCB *aio;
                aio=DI_get_aiocb();
#ifdef dr6_us5
                aio->aio.aio_filedes=diop->di_fd;
#else
                aio->aio.aio_fildes=diop->di_fd;
#endif /* dr6_us5 */
#ifdef LARGEFILE64
                if(aio_fsync64( O_SYNC, &aio->aio))
#elif defined(any_aix)
                if(fsync( aio->aio.aio_fildes ))
#else
                if(aio_fsync( O_SYNC, &aio->aio))
#endif /* LARGEFILE64 */
                {
	        SETCLERR(err_code, 0, ER_fsync);
                    small_status = FAIL;
                    break;
                }
                else
                {
                    if( (small_status=CSsuspend( CS_DIOW_MASK, 0, 0) ) != OK)
                    {
                        DIlru_set_di_error( &small_status, err_code, 
				DI_LRU_CSSUSPEND_ERR, DI_GENERAL_ERR);
		        break;
                    }
#if defined(axp_osf) 
                    if (  (aio_error(&aio->aio)) != 0 )
#else
#ifdef LARGEFILE64
                    if (  (aio_error64(&aio->aio)) != 0 )
#else /* LARGEFILE64 */
                    if (  (aio_error(&aio->aio)) != 0 )
#endif /* LARGEFILE64 */
#endif
                    {
	                SETCLERR(err_code, 0, ER_fsync);
	                small_status = FAIL;
                        break;
                    }
                }
            }
            else 
#endif /* xCL_ASYNC_IO */
	    if (FSYNC(diop->di_fd) < 0)
	    {
#ifdef xCL_092_NO_RAW_FSYNC
		/* AIX returns EINVAL on character special files */
		if (errno != EINVAL) 
#endif /* xCL_092_NO_RAW_FSYNC */
		{
	            SETCLERR(err_code, 0, ER_fsync);
	            small_status = FAIL;
		}
	    }
	}

    } while (FALSE);

    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 );
}
Пример #7
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);
}
Пример #8
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);
}
Пример #9
0
/*
** Name: scs_check_external_password 
**
** Description:
**	Check the external password for a role
**
** Inputs:
**	scb 		- SCB
**
** 	authname 	- Role/User name being checked
**
**	password 	- Role/User password
**
**	auth_role	- TRUE if authenticating a role
**
** Returns:
**	E_DB_OK - Access is allowed
**
**	E_DB_WARN - Access is denied
**
**	E_DB_ERROR - Failure determining access
**
** History:
**	9-mar-94 (robf)
**		Created
**	11-mar-94 (robf)
**           Distinguish between access disallowed and some other
**	     error. Add SCF activity in case auth. server take a while
**	15-mar-94 (robf)
**	     Rework to allow for user or role authentication, add
**	     parameter auth_role. Make routine external, 
**	     name scs_check_external_password, and move to scseauth.c
**      22-mar-1996 (stial01)
**          Cast length passed to sc0m_allocate to i4.
**	16-jul-96 (stephenb)
**	    Add effective user to parameter list and pass to authentication
**	    server (fix primarily for ICE authentication, but useful 
**	    information for the user anyway).
**	16-Nov-1998 (jenjo02)
**	    When suspending on BIO read, use CS_BIOR_MASK.
*/
DB_STATUS
scs_check_external_password (
	SCD_SCB *scb, 
	DB_OWN_NAME *authname, 
	DB_OWN_NAME *e_authname,
	DB_PASSWORD *password,
	bool	    auth_role
)
{
    DB_STATUS 	status = E_DB_WARN;
    STATUS    	cl_stat;
    STATUS    	local_status;
    char 	pmname[64];
    char 	*pmvalue;
    char  	target[64];
    GCA_FS_PARMS fs_parms; 
    SCS_REBUFF   *re_buff = NULL;
    char	 *work_buff;
    i4		 resume = 0;
    CS_SID	 sid;
    PTR		 save_data_area;
    char	 *q;
    char	 *gcmvalue;
    i4	 	 error_index;
    i4	 error_status;
    char	 *act_string;
    char	 blank_string[32] = "";

    for (;;)
    {
	
	if (auth_role)
		act_string = "Validating external role password";
	else
		act_string = "Validating external user password";

	MEcopy((PTR)act_string, STlength(act_string),
				scb->scb_sscb.sscb_ics.ics_act1);
	scb->scb_sscb.sscb_ics.ics_l_act1 = (i4)STlength(act_string);
	/*
	** Find the authentication mechanism for this role
	*/
	if (auth_role)
	{
	    STprintf(pmname, "ii.$.secure.role_auth.%*s",
		scs_trimwhite(sizeof(*authname),
			(char*)authname), 
		(char*)authname);
	}
	else
	{
	    STprintf(pmname, "ii.$.secure.user_auth.%*s",
		scs_trimwhite(sizeof(*authname),
			(char*)authname), 
		(char*)authname);
	}
	cl_stat = PMget(pmname, &pmvalue);
	if (cl_stat != OK)
	{
	        sc0e_put(E_SC035A_EXTPWD_NO_AUTH_MECH, 0, 1,
		         scs_trimwhite(sizeof(*authname),
			      (char*)authname),
			(PTR)authname,
			0, (PTR)0,
			0, (PTR)0,
			0, (PTR)0,
			0, (PTR)0,
			0, (PTR)0 );
		status = E_DB_ERROR;
		break;
	}
	/*
	** Now we know the target mechanism, set up target destination
	**
	** Legal values are either 'value' which maps to value/authsvr
	** or @value which is sent untranslated. 
	*/
	if (*pmvalue != '@')
		STprintf(target,"%s/authsvr",pmvalue);
	else
		STprintf(target,"%s", pmvalue+1);
	/*
	** Allocate buffer for processing the request
	*/
        status = sc0m_allocate(SCU_MZERO_MASK,
		    (i4)sizeof(SCS_REBUFF),
		    DB_SCF_ID,
		    (PTR)SCS_MEM,
		    SCRE_TAG,
		    (PTR*)&re_buff);
        if (status != E_DB_OK)
        {
		/* sc0m_allocate puts error codes in return status */
		sc0e_0_put(status, 0);
		status = E_DB_ERROR;
		break;
    	}
	work_buff = re_buff->work_buff;
	gcmvalue = re_buff->gcmvalue;

	CSget_sid(&sid);

	save_data_area = work_buff;
	/*
	** Build the fastselect request
	*/
	fs_parms.gca_user_name = NULL;
	fs_parms.gca_password = NULL;
	fs_parms.gca_account_name = NULL;
	fs_parms.gca_completion = cep_complete;
	fs_parms.gca_closure = NULL;
	fs_parms.gca_peer_protocol = GCA_PROTOCOL_LEVEL_61;
	fs_parms.gca_partner_name = target;
	fs_parms.gca_modifiers = GCA_RQ_GCM;
	fs_parms.gca_buffer = work_buff;
	fs_parms.gca_b_length = RQ_BUFF_SIZE;
	fs_parms.gca_message_type = GCM_SET;

	q = save_data_area;
	q += sizeof(i4);	/* Past error_status */
	q += sizeof(i4);	/* Past error_index */
	q += sizeof(i4);	/* Past future[0] */
	q += sizeof(i4);	/* Past future[1] */
	q += gcm_put_int(q, -1);/* Client perms */
	q += gcm_put_int(q, 1); /* Row count */
	q += gcm_put_int(q, 1); /* Element count */
	if (auth_role)
	    q += gcm_put_str(q, "exp.scf.auth_server.role_authenticate"); /* Class id */
	else
	    q += gcm_put_str(q, "exp.scf.auth_server.user_authenticate"); /* Class id */
	q += gcm_put_str(q, "0"); 		  /* Instance */
	/*
	** Now build the value.
	** This consists of:
	** Role:
	**  flag 	 - 4 byte integer, currently 0
	**  real user 	 - 32 byte blank-padded
	**  effective user - 32 byte blank-padded
	**  role         - 32 byte blank-padded
	**  password     - 24 byte blank-padded
	** User:
	**  flag 	 - 4 byte integer, currently 1
	**  real user 	 - 32 byte blank-padded
	**  effective user - 32 byte blank-padded
	**  password     - 24 byte blank-padded
	** These are all padded into a single GCM value.
	** Note: This assumes no NULL values in any of the fields.
	*/
	if (auth_role)
	{
	    STprintf(gcmvalue,"%-4.4s%32.32s%32.32s%32.32s%-24.24s",
		"0",
		(char*)&scb->scb_sscb.sscb_ics.ics_rusername,
		e_authname ? (char*)e_authname : blank_string,
		(char*)authname,
		(char*)password);
	}
	else
	{
	    STprintf(gcmvalue,"%-4.4s%32.32s%32.32s%-24.24s",
		"1",
		(char*)authname,
		e_authname ? (char*)e_authname : blank_string,
		(char*)password);
	}
	q += gcm_put_str(q, gcmvalue );	  	  /* Value */
	fs_parms.gca_msg_length = (i4)(q - save_data_area);
	break;
    }

    /*
    ** Now do the fastselect
    */
    resume = 0;
    if (status == E_DB_OK)
    do 
    {

	cl_stat = IIGCa_call(GCA_FASTSELECT,
			(GCA_PARMLIST *)&fs_parms,
			GCA_ASYNC_FLAG | GCA_ALT_EXIT | resume,
			(PTR)CS_find_scb(sid),
			(i4) -1,
			&local_status);
        if (cl_stat != OK)
        {
	    sc0e_0_put(cl_stat, 0);
	    sc0e_0_put(E_SC0357_EXTPWD_GCA_FASTSELECT, 0);
	    status = E_DB_ERROR;
	    break;
        }
        else
        {
            /* wait for completion routine to wake us */
            cl_stat = CSsuspend(CS_BIOR_MASK, 0, 0);
            if (cl_stat != OK)
            {
	        sc0e_0_put(cl_stat, 0);
	        sc0e_0_put(E_SC0356_EXTPWD_GCA_CSSUSPEND, 0);
	        status = E_DB_ERROR;
		resume = 0;
		break;
            }
            else                /* completion handler called */
            {
                switch ( cl_stat = fs_parms.gca_status )
                {
                case OK:

                    resume = 0;
                    break;

                case E_GCFFFE_INCOMPLETE:

                    resume = GCA_RESUME;
                    break;

                case E_GC0032_NO_PEER:
		case E_GC0138_GCN_NO_SERVER:
		case E_GC0139_GCN_NO_DBMS:

                    resume = 0;

		    sc0e_put(E_SC0355_EXTPWD_GCA_NOPEER, 0, 2,
				 scs_trimwhite(sizeof(*authname),
				      (char*)authname),
				(PTR)authname,
				(i4)STlength(target),
				(PTR)target,
		     		0, (PTR)0,
		     		0, (PTR)0,
		     		0, (PTR)0,
		     		0, (PTR)0 );
		    status = E_DB_ERROR;
                    break;

                default:

                    resume = 0;

	       	    sc0e_0_put(cl_stat, 0);
		    sc0e_0_put(E_SC0354_EXTPWD_GCA_COMPLETION, 0);
		    status = E_DB_ERROR;
                    break;
                }
            }
        }
    } while( resume != 0 );
    /*
    ** Check if select worked OK, if not skip to the end
    */
    if (status == E_DB_OK)
    {
	/*
	** Got result of fastselect, so unpack and see what happened
	*/
	q = save_data_area;
	q += gcm_get_int(q, &error_status);
	q += gcm_get_int(q, &error_index);
	if (error_status != 0)
	{
	   if (error_index == -1)
	   {
	       	sc0e_0_put(error_status, 0);
		sc0e_0_put(E_SC0359_EXTPWD_GCM_ERROR, 0);
	        status = E_DB_ERROR;
	   }
	   else
	   {
		/* Access is denied */
		status = E_DB_WARN;
	    }
	}
	else
	{
		/* Access is allowed */
		status = E_DB_OK;
	}
    }

    /* Reset activity */
    scb->scb_sscb.sscb_ics.ics_l_act1 = 0;

    /*
    ** Free buffer if allocated
    */
    if (re_buff)
    {
	if (sc0m_deallocate(0, (PTR *) &re_buff) != E_DB_OK)
	{
	    sc0e_0_put(status, 0);
	}
    }
    return(status);
}
Пример #10
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);
}