/* ** 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); }
/* ** 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); }
/* ** 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); }
/*{ ** 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); }
/*{ ** 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 ); }
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 ); }
/*{ ** ** 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); }
/*{ ** ** 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); }
/* ** 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); }
/*{ ** ** 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); }