int gcadm_format_err_data( char * buffer, char * sqlstate, i4 error_code, i4 error_len, char * error_text ) { char *er_data; i4 one = 1, zero = 0; i4 data_type = DB_CHA_TYPE; i4 ss_code, severity = GCA_ERFORMATTED; i4 msg_len; if ( GCADM_global.gcadm_trace_level >= 5 ) TRdisplay( "%4d GCADM format_err_data: error_code= %d\n", -1, error_code ); /* ** Set default sqlstate */ if ( sqlstate == NULL ) sqlstate = SS50000_MISC_ERRORS; ss_code = ss_encode( sqlstate ); /* ** Format GCA_ER_DATA object */ er_data = (char *) buffer; if ( ( error_code == FAIL ) || ( error_code == OK )) er_data += GCA_PUTI4_MACRO( &zero, er_data); /* gca_l_e_element */ else { er_data += GCA_PUTI4_MACRO( &one, er_data); /* gca_l_e_element */ er_data += GCA_PUTI4_MACRO( &ss_code, er_data );/* gca_id_error */ er_data += GCA_PUTI4_MACRO( &zero, er_data); /* gca_id_server */ er_data += GCA_PUTI4_MACRO( &zero, er_data); /* gca_server_type */ er_data += GCA_PUTI4_MACRO( &severity, er_data );/* gca_serverity */ er_data += GCA_PUTI4_MACRO( &error_code, er_data);/* gca_local_error */ /* ** Check to see if there is error text */ if ( error_len == 0 || ! error_text ) er_data += GCA_PUTI4_MACRO( &zero, er_data);/* gca_l_error_parm */ else { er_data += GCA_PUTI4_MACRO( &one, er_data); /* gca_l_error_parm */ er_data += GCA_PUTI4_MACRO( &data_type, er_data ); /* gca_type */ er_data += GCA_PUTI4_MACRO( &zero, er_data ); /* gca_precision */ /* ** Calculate the message len to ensure not over max buffer len */ msg_len = er_data - (char *)buffer + sizeof(i4); if ( (error_len + msg_len) > GCADM_global.gcadm_buff_len ) error_len = GCADM_global.gcadm_buff_len - msg_len; er_data += GCA_PUTI4_MACRO( &error_len, er_data); /* gca_l_value */ er_data += GCA_PUTBUF_MACRO( error_text, error_len, er_data); /* gca_value */ } } return( er_data - (char *)buffer ); }
static void gcadm_complete( PTR ptr ) { GCADM_RCB *rcb = (GCADM_RCB *)ptr; GCADM_SCB *scb = rcb->scb; /* ** Check for request failure or convert request ** type to the associated request completion. ** if term state, we don't care if request is complete or failed ** return to caller. ** */ if ( scb->parms.gca_all_parm.gca_status == E_GCFFFE_INCOMPLETE ) { gcadm_resume ( rcb ); return; } if ( GCADM_global.gcadm_state != GCADM_ACTIVE ) { if ( GCADM_global.gcadm_trace_level >= 1 ) TRdisplay( "%4d GCADM complete: ADM not active\n", -1 ); if ( rcb->operation == GCA_DISASSOC ) gcadm_free_scb( scb ); gcadm_free_rcb( rcb ); return; } if ( GCADM_global.gcadm_trace_level >= 4 ) TRdisplay( "%4d GCADM complete: entry\n", scb->aid); if ( GCADM_global.gcadm_trace_level >= 5 ) TRdisplay( "%4d GCADM complete: GCA operation= %d, status =%d\n", scb->aid, rcb->operation, scb->parms.gca_all_parm.gca_status ); if ( scb->parms.gca_all_parm.gca_status != OK) { if ( GCADM_global.gcadm_trace_level >= 1 ) TRdisplay( "%4d GCADM complete: GCA operation= %d failed \n", scb->aid, rcb->operation ); rcb->event = ADMI_RQST_FAIL; rcb->status = scb->parms.gca_all_parm.gca_status; gcadm_event( rcb ); return; } switch( rcb->operation ) { case GCA_RECEIVE : switch (scb->parms.gca_rv_parm.gca_message_type) { case GCA_RELEASE: rcb->event = ADMI_RECV_RELEASE; break; case GCA_MD_ASSOC: rcb->event = ADMI_RECV_MDASSOC; break; case GCA_QUERY: rcb->event = ADMI_RECV_QUERY; break; default: if ( GCADM_global.gcadm_trace_level >= 1 ) TRdisplay( "%4d GCADM complete: recv unexpected msg %d \n", scb->aid, scb->parms.gca_rv_parm.gca_message_type); rcb->status = E_GC5004_INVALID_MSG; rcb->event = ADMI_RECV_INVALID; break; } break; case GCA_SEND: rcb->event = ADMI_SEND_CMPL; break; case GCA_DISASSOC: rcb->event = ADMI_DISC_DONE; break; default : rcb->status = E_GC5005_INTERNAL_ERROR; rcb->event = ADMI_RQST_FAIL; return; } gcadm_event( rcb ); return; }
/* ** Name: sxapo_init_cnf - Initialize SXAPO configuration from the PM file. ** ** Description: ** This routine initializes the SXAPO configuration from the ** PM configuration file. ** ** Inputs: ** None. ** ** Outputs: ** err_code Error code returned to caller. ** ** Returns: ** DB_STATUS ** ** History: ** 6-jan-94 (stephenb) ** Initial creation. */ DB_STATUS sxapo_init_cnf( i4 *err_code) { DB_STATUS status = E_DB_OK; STATUS clstat; i4 local_err; char *pmfile; char *pmvalue; *err_code = E_SX0000_OK; for (;;) { /* ** Allow private override on PM file */ NMgtAt("II_SXF_PMFILE", &pmfile); if (pmfile && *pmfile) { LOCATION pmloc; TRdisplay("Loading SXF-PM file '%s'\n",pmfile); LOfroms(PATH & FILENAME, pmfile, &pmloc); if(PMload(&pmloc,NULL)!=OK) TRdisplay("Error loading PMfile '%s'\n",pmfile); } /* ** Get auditing status */ if (PMget(SX_C2_MODE,&pmvalue) == OK) { if (!STbcompare(pmvalue, 0, SX_C2_MODE_ON, 0, TRUE)) { /* ** Auditing on */ Sxapo_cb->sxapo_status=SXAPO_ACTIVE; } else if ((STbcompare(pmvalue, 0, SX_C2_MODE_OFF, 0, TRUE)!=0)) { /* ** Niether ON nor OFF, Invalid mode */ *err_code=E_SX1061_SXAP_BAD_MODE; break; } } else { /* ** No value, this is an error */ *err_code=E_SX1061_SXAP_BAD_MODE; break; } /* ** Get action on error */ if ((PMget("II.*.C2.ON_ERROR",&pmvalue) == OK)) { if (!STcasecmp(pmvalue, "STOPAUDIT" )) { Sxf_svcb->sxf_act_on_err=SXF_ERR_STOPAUDIT; } else if (!STcasecmp(pmvalue, "SHUTDOWN" )) { Sxf_svcb->sxf_act_on_err=SXF_ERR_SHUTDOWN; } else { /* ** Invalid value */ *err_code=E_SX1060_SXAP_BAD_ONERROR; break; } } else { /* ** No value, this is an error */ *err_code=E_SX1060_SXAP_BAD_ONERROR; break; } break; } /* handle errors */ if (*err_code != E_SX0000_OK) { _VOID_ ule_format(*err_code, NULL, ULE_LOG, NULL, NULL, 0L, NULL, &local_err, 0); *err_code = E_SX1020_SXAP_INIT_CNF; status = E_DB_ERROR; } return (status); }
void IIodbc_timeOutThread() { QUEUE *q, *p, *pq; pENV penv; pDBC pdbc; RETCODE rc; SYSTIME expire_time; TM_STAMP stamp; char stampStr[TM_SIZE_STAMP]; ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread() with timeout %d\n", IIodbc_cb.timeout); while(TRUE) { /* ** Search the pool every thirty seconds and check for expired ** connections. Force disconnect and free from the pool ** if the connection handle has passed the expiration time. ** Note that the CLI and driver connection handles are not ** freed. */ PCsleep(30000); TMget_stamp(&stamp); TMstamp_str(&stamp, stampStr); ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread woke up at %s\n", stampStr); TMnow(&expire_time); if (IIodbc_cb.pooling == DRIVER_POOL) { applyLock(SQL_HANDLE_IIODBC_CB, NULL); for (q = IIodbc_cb.pool_q.q_prev; q!= &IIodbc_cb.pool_q; q = p) { ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread: driver pool count is %d\n", IIodbc_cb.pool_count); p = q->q_prev; pdbc = (pDBC)((pPOOL)q)->pdbc; ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread: found conn handle %p with time diff %d\n",pdbc, expire_time.TM_secs - pdbc->expire_time.TM_secs); if (expire_time.TM_secs - pdbc->expire_time.TM_secs > IIodbc_cb.timeout) { /* ** Note that the connection handle is not freed, only ** removed from the pool. */ ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread: EXPIRED. pdbc time is %d vs %d\n", pdbc->expire_time.TM_secs, expire_time.TM_secs); rc = IIDisconnect(pdbc->hdr.driverHandle); QUremove(q); MEfree((PTR)q); IIodbc_cb.pool_count -= 1; ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("new pool count is %d\n",IIodbc_cb.pool_count); applyLock(SQL_HANDLE_DBC, pdbc); pdbc->hdr.state = C2; releaseLock(SQL_HANDLE_DBC, pdbc); } } releaseLock(SQL_HANDLE_IIODBC_CB, NULL); } else { for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q; q = q->q_prev) { penv = (pENV)q; TRdisplay("Found env handle %p\n",penv); applyLock(SQL_HANDLE_ENV, penv); for (pq = penv->pool_q.q_prev; pq != &penv->pool_q; pq = p) { ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("Env pool count is %d\n",penv->pool_count); p = q->q_prev; pdbc = (pDBC)((pPOOL)pq)->pdbc; ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_TimeOutThread: Found conn handle %p with time diff %d\n",pdbc, expire_time.TM_secs - pdbc->expire_time.TM_secs); if (expire_time.TM_secs - pdbc->expire_time.TM_secs > 1) { ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread: EXPIRED. pdbc time is %d vs %d\n", pdbc->expire_time.TM_secs, expire_time.TM_secs); rc = IIDisconnect(pdbc->hdr.driverHandle); QUremove(q); MEfree((PTR)q); penv->pool_count -= 1; ODBC_EXEC_TRACE(ODBC_EX_TRACE) ("IIodbc_timeOutThread: new pool count is %d\n", penv->pool_count); } } releaseLock(SQL_HANDLE_ENV, penv); } /* for (q = IIodbc_cb.env_q.q_prev; q!= &IIodbc_cb.env_q; q = q->q_prev) */ } /* if (IIodbc_cb.pooling == DRIVER_POOL) */ } /* while (TRUE) */ }
/*{ ** ** 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: 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); }
/* And now the real thing */ static VOID opc_exnodearrcnt( OPS_STATE *global, QEN_NODE *node, i4 *arrcnts, PTR rowmap) { QEN_OJINFO *ojinfop; QEN_PART_INFO *partp; QEN_PART_QUAL *pqual; QEN_SJOIN *sjnp; QEN_KJOIN *kjnp; QEN_TJOIN *tjnp; QEN_HJOIN *hjnp; QEN_SEJOIN *sejnp; QEN_SORT *srtp; QEN_TPROC *tprocp; QEN_TSORT *tsrtp; QEN_ORIG *origp; QEN_QP *qpp; QEN_EXCH *exchp; QEF_QP_CB *qp = global->ops_cstate.opc_qp; QEF_RESOURCE *resp; QEF_VALID *vlp; QEF_AHD *act; i4 i, j, k; i4 dmrix; bool endloop; /* Loop (recurse on left, iterate on right) and switch to process ** each node in subtree. */ for ( ; ; ) { if (node == (QEN_NODE *) NULL) return; /* just in case */ opc_exnheadcnt(global, node, arrcnts, rowmap); /* count node header indexes */ ojinfop = (QEN_OJINFO *) NULL; partp = (QEN_PART_INFO *) NULL; pqual = NULL; dmrix = -1; switch (node->qen_type) { case QE_CPJOIN: case QE_FSMJOIN: case QE_ISJOIN: sjnp = &node->node_qen.qen_sjoin; ojinfop = sjnp->sjn_oj; if (sjnp->sjn_krow >= 0) BTset(sjnp->sjn_krow, rowmap); if (sjnp->sjn_hfile >= 0) arrcnts[IX_HLD]++; if (sjnp->sjn_itmat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sjnp->sjn_okmat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sjnp->sjn_okcompare != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sjnp->sjn_joinkey != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sjnp->sjn_jqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; opc_exnodearrcnt(global, sjnp->sjn_out, arrcnts, rowmap); node = sjnp->sjn_inner; break; case QE_KJOIN: kjnp = &node->node_qen.qen_kjoin; ojinfop = kjnp->kjoin_oj; partp = kjnp->kjoin_part; pqual = kjnp->kjoin_pqual; if ((dmrix = kjnp->kjoin_get) >= 0) arrcnts[IX_DMR]++; if (kjnp->kjoin_krow >= 0) BTset(kjnp->kjoin_krow, rowmap); if (kjnp->kjoin_key != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (kjnp->kjoin_kqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (kjnp->kjoin_kcompare != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (kjnp->kjoin_iqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (kjnp->kjoin_jqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; node = kjnp->kjoin_out; break; case QE_TJOIN: tjnp = &node->node_qen.qen_tjoin; ojinfop = tjnp->tjoin_oj; partp = tjnp->tjoin_part; pqual = tjnp->tjoin_pqual; if ((dmrix = tjnp->tjoin_get) >= 0) arrcnts[IX_DMR]++; if (tjnp->tjoin_orow >= 0) BTset(tjnp->tjoin_orow, rowmap); if (tjnp->tjoin_irow >= 0) BTset(tjnp->tjoin_irow, rowmap); if (tjnp->tjoin_jqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (tjnp->tjoin_isnull != (QEN_ADF *) NULL) arrcnts[IX_CX]++; node = tjnp->tjoin_out; break; case QE_HJOIN: hjnp = &node->node_qen.qen_hjoin; ojinfop = hjnp->hjn_oj; pqual = hjnp->hjn_pqual; arrcnts[IX_HSH]++; if (hjnp->hjn_brow >= 0) BTset(hjnp->hjn_brow, rowmap); /* prow is probably already counted as qen_row but make sure */ if (hjnp->hjn_prow >= 0) BTset(hjnp->hjn_prow, rowmap); if (hjnp->hjn_dmhcb >= 0) arrcnts[IX_DMH]++; if (hjnp->hjn_btmat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (hjnp->hjn_ptmat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (hjnp->hjn_jqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; opc_exnodearrcnt(global, hjnp->hjn_out, arrcnts, rowmap); node = hjnp->hjn_inner; break; case QE_SEJOIN: sejnp = &node->node_qen.qen_sejoin; ojinfop = (QEN_OJINFO *) NULL; partp = (QEN_PART_INFO *) NULL; /* if (sejnp->sejn_hget >= 0) - these aren't ref'ed in QEF arrcnts[IX_DMR]++; */ if (sejnp->sejn_hfile >= 0) arrcnts[IX_HLD]++; if (sejnp->sejn_itmat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sejnp->sejn_ccompare != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sejnp->sejn_oqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (sejnp->sejn_okmat != NULL) arrcnts[IX_CX]++; if (sejnp->sejn_kcompare != NULL) arrcnts[IX_CX]++; if (sejnp->sejn_kqual != NULL) arrcnts[IX_CX]++; opc_exnodearrcnt(global, sejnp->sejn_out, arrcnts, rowmap); node = sejnp->sejn_inner; break; case QE_TSORT: tsrtp = &node->node_qen.qen_tsort; pqual = tsrtp->tsort_pqual; if (tsrtp->tsort_get >= 0) arrcnts[IX_DMR]++; if (tsrtp->tsort_load >= 0) arrcnts[IX_DMR]++; if (tsrtp->tsort_create >= 0) arrcnts[IX_DMT]++; if (tsrtp->tsort_shd >= 0) arrcnts[IX_SHD]++; if (tsrtp->tsort_mat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; node = tsrtp->tsort_out; break; case QE_SORT: srtp = &node->node_qen.qen_sort; if (srtp->sort_load >= 0) arrcnts[IX_DMR]++; if (srtp->sort_create >= 0) arrcnts[IX_DMT]++; if (srtp->sort_shd >= 0) arrcnts[IX_SHD]++; if (srtp->sort_mat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; node = srtp->sort_out; break; case QE_ORIG: case QE_ORIGAGG: origp = &node->node_qen.qen_orig; if ((dmrix = origp->orig_get) >= 0) { arrcnts[IX_DMR]++; } partp = origp->orig_part; pqual = origp->orig_pqual; if (origp->orig_qual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; node = (QEN_NODE *) NULL; break; case QE_QP: qpp = &node->node_qen.qen_qp; if (qpp->qp_qual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; /* Process action headers anchored in QP node. */ for (act = node->node_qen.qen_qp.qp_act; act; act = act->ahd_next) opc_exactarrcnt(global, act, arrcnts, rowmap); return; case QE_EXCHANGE: exchp = &node->node_qen.qen_exch; if (exchp->exch_mat != (QEN_ADF *) NULL) arrcnts[IX_CX]++; /* Don't probe below 1:N exchanges, they'll do their own setup. ** 1:1 exchange depends on parent, so keep going. */ if (exchp->exch_ccount > 1) return; node = exchp->exch_out; break; case QE_TPROC: tprocp = &node->node_qen.qen_tproc; if (tprocp->tproc_parambuild != NULL) arrcnts[IX_CX]++; if (tprocp->tproc_qual != NULL) arrcnts[IX_CX]++; return; /* Nothing else interesting */ default: TRdisplay("Unexpected QP node type %d under exch\n",node->qen_type); opx_error(E_OP068E_NODE_TYPE); } /* end of switch */ /* Node specific bits have been set - now go over OJ and ** partition stuff (if any). */ if (ojinfop) { if (ojinfop->oj_heldTidRow >= 0) BTset(ojinfop->oj_heldTidRow, rowmap); if (ojinfop->oj_ijFlagsRow >= 0) BTset(ojinfop->oj_ijFlagsRow, rowmap); if (ojinfop->oj_resultEQCrow >= 0) BTset(ojinfop->oj_resultEQCrow, rowmap); if (ojinfop->oj_specialEQCrow >= 0) BTset(ojinfop->oj_specialEQCrow, rowmap); if (ojinfop->oj_tidHoldFile >= 0) arrcnts[IX_HLD]++; if (ojinfop->oj_ijFlagsFile >= 0) arrcnts[IX_HLD]++; if (ojinfop->oj_innerJoinedTIDs) arrcnts[IX_TTAB]++; if (ojinfop->oj_oqual != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (ojinfop->oj_equal != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (ojinfop->oj_lnull != (QEN_ADF *) NULL) arrcnts[IX_CX]++; if (ojinfop->oj_rnull != (QEN_ADF *) NULL) arrcnts[IX_CX]++; } if (partp) { if (partp->part_groupmap_ix >= 0) BTset(partp->part_groupmap_ix, rowmap); if (partp->part_ktconst_ix >= 0) BTset(partp->part_ktconst_ix, rowmap); if (partp->part_knokey_ix >= 0) BTset(partp->part_knokey_ix, rowmap); } /* Part-qual structures contain mini-programs that must be ** scanned to gather up row numbers. */ if (pqual != NULL) { QEN_PQ_EVAL *pqe; arrcnts[IX_PQUAL]++; if (pqual->part_constmap_ix >= 0) BTset(pqual->part_constmap_ix, rowmap); if (pqual->part_lresult_ix >= 0) BTset(pqual->part_lresult_ix, rowmap); if (pqual->part_work1_ix >= 0) BTset(pqual->part_work1_ix, rowmap); pqe = pqual->part_const_eval; if (pqe != NULL) opc_arrcnt_pqe(pqe, arrcnts, rowmap); pqe = pqual->part_join_eval; if (pqe != NULL) opc_arrcnt_pqe(pqe, arrcnts, rowmap); } /* If TJOIN, KJOIN or ORIG, locate DMT_CB index in valid's. */ if (dmrix >= 0) for (resp = qp->qp_resources, endloop = FALSE; resp && !endloop; resp = resp->qr_next) if (resp->qr_type == QEQR_TABLE) for (vlp = resp->qr_resource.qr_tbl.qr_lastvalid; vlp && !endloop; vlp = vlp->vl_next) if (dmrix == vlp->vl_dmr_cb) { arrcnts[IX_DMT]++; endloop = TRUE; if (vlp->vl_partition_cnt > 1) arrcnts[IX_DMR]++; /* set master DMR_CB, too */ } if (node == (QEN_NODE *) NULL) return; } /* end of for ( ; ; ) */ }
/*{ ** Name: CK_subst - build a CK command from template and requirements ** ** Description: ** This function will search a CK command template file for ** a line meeting the requirements of the inputs and will substitute ** various esacpe sequences with other strings such as file names. ** ** Based on a II_subst of the 5.0 UNIX CL. ** ** Inputs: ** comlen length of cline space ** oper operation - one of 'B'egin, 'E'nd, 'W'ork ** dev device type - one of 'T'ape, 'D'isk ** dir direction - one of 'S'ave, 'R'estore ** type type (device type) 0 for disk, 1 for tape ** locnum location number (sequence or quantity) ** di_l_path length of di path string ** di_path di path string ** ckp_l_path length of checkpoint path string ** ckp_path checkpoint path string ** ckp_l_file length of checkpoint file string ** ckp_file checkpoint file string ** ** Outputs: ** cline space for generated command ** ** Returns: ** CK_FILENOTFOUND template file can't be found ** E_DB_OK ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 27-oct-88 (anton) ** Created. ** 16-may-90 (walt) ** Return CK_FILENOTFOUND if the template file (cktmpl.def) can't ** be opened. ** 23-may-1994 (bryanp) ** Modified Walt's 16-may-90 fix to use CK_TEMPLATE_MISSING, rather ** than CK_FILENOTFOUND, since CK_TEMPLATE_MISSING is a more ** specific, and therefore hopefully more useful, error message. ** 03-jan-1995 (dougb) ** Cross-integrate Unix change 415365: ** 02-dec-1994 (andyw) ** Check on granularity for partial backup */ STATUS CK_subst( char *cline, i4 comlen, char oper, char dev, char dir, u_i4 type, u_i4 locnum, u_i4 di_l_path, char *di_path, u_i4 ckp_l_path, char *ckp_path, u_i4 ckp_l_file, char *ckp_file) { STATUS ret_val = OK; auto LOCATION loc; auto char *s; auto FILE *fp; auto char *cp; char *command; command = MEreqmem(0, comlen, TRUE, &ret_val); if (!ret_val) { NMgtAt("II_CKTMPL_FILE", &s); if (s == NULL || *s == EOS) { ret_val = NMf_open("r", "cktmpl.def", &fp); } else { LOfroms( PATH & FILENAME, s, &loc ); ret_val = SIopen( &loc, "r", &fp); } if (ret_val) { ret_val = CK_TEMPLATE_MISSING; } } /* find command line - skip comments and blank lines */ if (!ret_val) { while ((ret_val = SIgetrec(command, comlen, fp)) == OK) { if (*command == '\n') { continue; } if (command[0] == oper && (command[1] == dir || command[1] == 'E') && (command[2] == dev || command[2] == 'E') && (command[3] == 'D' || command[3] == 'E') && command[4] == ':') { break; } } } _VOID_ SIclose(fp); if (!ret_val) { /* found the line - do the substitution */ s = command + 5; cp = cline; while (*s != '\n') { if (*s == '%') { switch (*++s) { case '%': *cp++ = '%'; break; case 'D': CK_lfill(&cp, di_l_path, di_path); break; case 'C': CK_lfill(&cp, ckp_l_path, ckp_path); break; case 'F': CK_lfill(&cp, ckp_l_file, ckp_file); break; case 'A': CK_lfill(&cp, ckp_l_path, ckp_path); # ifdef UNIX *cp++ = '/'; # endif CK_lfill(&cp, ckp_l_file, ckp_file); break; case 'T': *cp++ = type ? '1' : '0'; break; case 'N': CVna(locnum, cp); while (*cp) cp++; break; default: *cp++ = '%'; *cp++ = *s; } ++s; } else { *cp++ = *s++; } } *cp = EOS; } # ifdef xDEBUG TRdisplay("CK_subst %c %c %c: %s\n", oper, dir, dev, cline); # endif return(ret_val); }
/*{ ** Name: OPC_EXNODEARRSET - set DSH ptr array indexes in exch_array1/2 ** ** Description: Analyze QP subtree saving DSH ptr array indexes to indicate ** the buffers and structures that need to be allocated for child ** thread DSH ** ** Inputs: ** ** Outputs: ** Returns: ** Exceptions: ** ** Side Effects: ** ** History: ** 1-mar-04 (inkdo01) ** Written for || query processing. ** 28-apr-04 (inkdo01) ** Forgot to set bits for QEN_STATUS and hash structures. ** 11-june-04 (inkdo01) ** Code to recurse on actions owned by QP node. ** 15-june-04 (inkdo01) ** Remove sejn_hget from bit map - not used (and not filled in) ** in QEF. ** 17-june-04 (inkdo01) ** Add logic to set QEN_PQ_RESET to allow earlier thread shutdown. ** 22-july-04 (inkdo01) ** Reworked to produce arrays of DSH ptr array indexes. ** 27-aug-04 (inkdo01) ** Forgot QEN_PART_INFOs addr'ed from ORIG nodes. ** 10-sep-04 (inkdo01) ** Remove QEN_PART_INFO entities from arrays. ** 15-May-2010 (kschendel) b123565 ** Add missing TPROC case to prevent looping; add default. ** Continue below 1:1 exch, as they depend on parents. ** Delete "resettable", done as a separate pass in opcran now. ** 19-May-2010 (kschendel) b123759 ** ijFlagsFile is a hold, not a row. ** Don't need to do rows here, done via bitmap. */ static VOID opc_exnodearrset( OPS_STATE *global, QEN_NODE *node, i2 *array1, i4 *array2, i4 *arrcnts) { QEN_OJINFO *ojinfop; QEN_PART_QUAL *pqual; QEN_SJOIN *sjnp; QEN_KJOIN *kjnp; QEN_TJOIN *tjnp; QEN_HJOIN *hjnp; QEN_SEJOIN *sejnp; QEN_SORT *srtp; QEN_TPROC *tprocp; QEN_TSORT *tsrtp; QEN_ORIG *origp; QEN_QP *qpp; QEN_EXCH *exchp; QEF_QP_CB *qp = global->ops_cstate.opc_qp; QEF_RESOURCE *resp; QEF_VALID *vlp; QEF_AHD *act; i4 i, j, k; i4 dmrix; bool endloop; /* Loop (recurse on left, iterate on right) and switch to process ** each node in subtree. */ for ( ; ; ) { if (node == (QEN_NODE *) NULL) return; /* just in case */ opc_exnheadset(global, node, array1, array2, arrcnts); /* set node header indexes */ ojinfop = (QEN_OJINFO *) NULL; pqual = NULL; dmrix = -1; switch (node->qen_type) { case QE_CPJOIN: case QE_FSMJOIN: case QE_ISJOIN: sjnp = &node->node_qen.qen_sjoin; ojinfop = sjnp->sjn_oj; if (sjnp->sjn_hfile >= 0) array1[arrcnts[IX_HLD]++] = sjnp->sjn_hfile; if (sjnp->sjn_itmat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sjnp->sjn_itmat->qen_pos; if (sjnp->sjn_okmat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sjnp->sjn_okmat->qen_pos; if (sjnp->sjn_okcompare != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sjnp->sjn_okcompare->qen_pos; if (sjnp->sjn_joinkey != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sjnp->sjn_joinkey->qen_pos; if (sjnp->sjn_jqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sjnp->sjn_jqual->qen_pos; opc_exnodearrset(global, sjnp->sjn_out, array1, array2, arrcnts); node = sjnp->sjn_inner; break; case QE_KJOIN: kjnp = &node->node_qen.qen_kjoin; ojinfop = kjnp->kjoin_oj; pqual = kjnp->kjoin_pqual; if ((dmrix = kjnp->kjoin_get) >= 0) array2[arrcnts[IX_DMR]++] = kjnp->kjoin_get; if (kjnp->kjoin_key != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = kjnp->kjoin_key->qen_pos; if (kjnp->kjoin_kqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = kjnp->kjoin_kqual->qen_pos; if (kjnp->kjoin_kcompare != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = kjnp->kjoin_kcompare->qen_pos; if (kjnp->kjoin_iqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = kjnp->kjoin_iqual->qen_pos; if (kjnp->kjoin_jqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = kjnp->kjoin_jqual->qen_pos; node = kjnp->kjoin_out; break; case QE_TJOIN: tjnp = &node->node_qen.qen_tjoin; ojinfop = tjnp->tjoin_oj; pqual = tjnp->tjoin_pqual; if ((dmrix = tjnp->tjoin_get) >= 0) array2[arrcnts[IX_DMR]++] = tjnp->tjoin_get; if (tjnp->tjoin_jqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = tjnp->tjoin_jqual->qen_pos; if (tjnp->tjoin_isnull != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = tjnp->tjoin_isnull->qen_pos; node = tjnp->tjoin_out; break; case QE_HJOIN: hjnp = &node->node_qen.qen_hjoin; ojinfop = hjnp->hjn_oj; pqual = hjnp->hjn_pqual; array1[arrcnts[IX_HSH]++] = hjnp->hjn_hash; if (hjnp->hjn_dmhcb >= 0) array2[arrcnts[IX_DMH]++] = hjnp->hjn_dmhcb; if (hjnp->hjn_btmat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = hjnp->hjn_btmat->qen_pos; if (hjnp->hjn_ptmat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = hjnp->hjn_ptmat->qen_pos; if (hjnp->hjn_jqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = hjnp->hjn_jqual->qen_pos; opc_exnodearrset(global, hjnp->hjn_out, array1, array2, arrcnts); node = hjnp->hjn_inner; break; case QE_SEJOIN: sejnp = &node->node_qen.qen_sejoin; ojinfop = (QEN_OJINFO *) NULL; /* if (sejnp->sejn_hget >= 0) - these aren't ref'ed in QEF array2[arrcnts[IX_DMR]++] = sejnp->sejn_hget; */ if (sejnp->sejn_hfile >= 0) array1[arrcnts[IX_HLD]++] = sejnp->sejn_hfile; if (sejnp->sejn_itmat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_itmat->qen_pos; if (sejnp->sejn_ccompare != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_ccompare->qen_pos; if (sejnp->sejn_oqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_oqual->qen_pos; if (sejnp->sejn_okmat != NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_okmat->qen_pos; if (sejnp->sejn_kcompare != NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_kcompare->qen_pos; if (sejnp->sejn_kqual != NULL) array2[arrcnts[IX_CX]++] = sejnp->sejn_kqual->qen_pos; opc_exnodearrset(global, sejnp->sejn_out, array1, array2, arrcnts); node = sejnp->sejn_inner; break; case QE_TSORT: tsrtp = &node->node_qen.qen_tsort; pqual = tsrtp->tsort_pqual; if (tsrtp->tsort_get >= 0) array2[arrcnts[IX_DMR]++] = tsrtp->tsort_get; if (tsrtp->tsort_load >= 0) array2[arrcnts[IX_DMR]++] = tsrtp->tsort_load; if (tsrtp->tsort_create >= 0) array2[arrcnts[IX_DMT]++] = tsrtp->tsort_create; if (tsrtp->tsort_shd >= 0) array1[arrcnts[IX_SHD]++] = tsrtp->tsort_shd; if (tsrtp->tsort_mat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = tsrtp->tsort_mat->qen_pos; node = tsrtp->tsort_out; break; case QE_SORT: srtp = &node->node_qen.qen_sort; if (srtp->sort_load >= 0) array2[arrcnts[IX_DMR]++] = srtp->sort_load; if (srtp->sort_create >= 0) array2[arrcnts[IX_DMT]++] = srtp->sort_create; if (srtp->sort_shd >= 0) array1[arrcnts[IX_SHD]++] = srtp->sort_shd; if (srtp->sort_mat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = srtp->sort_mat->qen_pos; node = srtp->sort_out; break; case QE_ORIG: case QE_ORIGAGG: origp = &node->node_qen.qen_orig; pqual = origp->orig_pqual; if ((dmrix = origp->orig_get) >= 0) { array2[arrcnts[IX_DMR]++] = origp->orig_get; } if (origp->orig_qual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = origp->orig_qual->qen_pos; node = (QEN_NODE *) NULL; break; case QE_QP: qpp = &node->node_qen.qen_qp; if (qpp->qp_qual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = qpp->qp_qual->qen_pos; /* Process action headers anchored in QP node. */ for (act = node->node_qen.qen_qp.qp_act; act; act = act->ahd_next) opc_exactarrset(global, act, array1, array2, arrcnts); return; case QE_EXCHANGE: exchp = &node->node_qen.qen_exch; if (exchp->exch_mat != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = exchp->exch_mat->qen_pos; /* Don't probe below 1:N exchanges, they'll do their own setup. ** 1:1 exchange depends on parent, so keep going. */ if (exchp->exch_ccount > 1) return; node = exchp->exch_out; break; case QE_TPROC: tprocp = &node->node_qen.qen_tproc; if (tprocp->tproc_parambuild != NULL) array2[arrcnts[IX_CX]++] = tprocp->tproc_parambuild->qen_pos; if (tprocp->tproc_qual != NULL) array2[arrcnts[IX_CX]++] = tprocp->tproc_qual->qen_pos; return; /* Nothing underneath */ default: TRdisplay("Unexpected QP node type %d under exch\n",node->qen_type); opx_error(E_OP068E_NODE_TYPE); } /* end of switch */ /* Node specific bits have been set - now go over OJ and ** partition stuff (if any). */ if (ojinfop) { if (ojinfop->oj_tidHoldFile >= 0) array1[arrcnts[IX_HLD]++] = ojinfop->oj_tidHoldFile; if (ojinfop->oj_ijFlagsFile >= 0) array1[arrcnts[IX_HLD]++] = ojinfop->oj_ijFlagsFile; if (ojinfop->oj_innerJoinedTIDs) array1[arrcnts[IX_TTAB]++] = ojinfop->oj_innerJoinedTIDs-> ttb_tempTableIndex; if (ojinfop->oj_oqual != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = ojinfop->oj_oqual->qen_pos; if (ojinfop->oj_equal != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = ojinfop->oj_equal->qen_pos; if (ojinfop->oj_lnull != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = ojinfop->oj_lnull->qen_pos; if (ojinfop->oj_rnull != (QEN_ADF *) NULL) array2[arrcnts[IX_CX]++] = ojinfop->oj_rnull->qen_pos; } if (pqual != NULL) { array1[arrcnts[IX_PQUAL]++] = pqual->part_pqual_ix; if (pqual->part_const_eval != NULL) array2[arrcnts[IX_CX]++] = pqual->part_const_eval->un.hdr.pqe_cx->qen_pos; if (pqual->part_join_eval != NULL) array2[arrcnts[IX_CX]++] = pqual->part_join_eval->un.hdr.pqe_cx->qen_pos; } /* If TJOIN, KJOIN or ORIG, locate DMT_CB index in valid's. */ if (dmrix >= 0) for (resp = qp->qp_resources, endloop = FALSE; resp && !endloop; resp = resp->qr_next) if (resp->qr_type == QEQR_TABLE) for (vlp = resp->qr_resource.qr_tbl.qr_lastvalid; vlp && !endloop; vlp = vlp->vl_next) if (dmrix == vlp->vl_dmr_cb) { array2[arrcnts[IX_DMT]++] = vlp->vl_dmf_cb; endloop = TRUE; if (vlp->vl_partition_cnt > 1) array2[arrcnts[IX_DMR]++] = dmrix - 1; /* set master DMR_CB, too */ } if (node == (QEN_NODE *) NULL) return; } /* end of for ( ; ; ) */ }
/*{ ** Name: opx_rverror - this routine will report another facility's error ** ** Description: ** This routine will log an error from another facility and the related ** optimizer error. ** ** Inputs: ** opfcb ptr to another facility's control block ** error optimizer error code to report ** facility ptr to facility's control block ** ** Outputs: ** Returns: ** VOID ** Exceptions: ** - internal exception generated ** ** Side Effects: ** the exception handling routines are responsible for ** deallocating OPF resources bound to this session. ** ** History: ** 3-jul-86 (seputis) ** initial creation ** 21-may-89 (jrb) ** now passes generic_error to opx_sccerror routine ** 24-oct-92 (andre) ** interfaces of ule_format() and opx_sccerror() have been changed to ** receive (DB_SQLSTATE *) ** 24-Oct-2008 (jonj) ** Replace ule_doformat with ule_format. [@history_line@]... */ VOID opx_rverror( OPF_CB *opfcb, DB_STATUS status, OPX_ERROR error, OPX_FACILITY facility) { DB_STATUS ule_status; /* return status from ule_format */ i4 ule_error; /* ule cannot format message */ char msg_buffer[DB_ERR_SIZE]; /* error message buffer */ i4 msg_buf_length; /* length of message returned */ i4 log; /* logging state */ DB_SQLSTATE sqlstate; opfcb->opf_errorblock.err_code = error; /* save error code */ opfcb->opf_errorblock.err_data = facility; /* save code ** from facility */ if ((error % 256) < 128) log = ULE_LOOKUP; /* lookup only user errors with range ** of 0-127 */ else log = ULE_LOG; /* log errors with range 128-255 */ #ifdef OPT_F031_WARNINGS /* if trace flag is set then warning or info errors will be reported */ if ( DB_SUCCESS_MACRO(status)) { OPS_CB *ops_cb; ops_cb = ops_getcb(); if (ops_cb && ( !ops_cb->ops_check || !opt_strace( ops_cb, OPT_F031_WARNINGS) )) return; } #endif ule_status = ule_format( error, (CL_SYS_ERR *)NULL, log, &sqlstate, msg_buffer, (i4) (sizeof(msg_buffer)-1), &msg_buf_length, &ule_error, 0); if (ule_status != E_DB_OK) { (VOID)STprintf(msg_buffer, "ULE error = %x\nOptimizer cannot be found - error no = %x Status = %x Facility error = %x \n", ule_error, error , status, facility); } else msg_buffer[msg_buf_length] = 0; /* null terminate */ /* FIXME - should check possible return status and generate a severe error ** unless it is simple (like cannot find message) */ { /* report any errors in the range 0 to 127 to the user */ DB_STATUS scf_status; if (facility) scf_status = opx_sccerror(E_DB_WARN, &sqlstate, error, msg_buffer,(i4)msg_buf_length); /* generate ** a warning, so that SCC_TRACE is ** used, this will ensure that ** SCC_ERROR will be called with ** the "facility" error code which ** will be the ingres user code ** which will be returned to the ** equel program */ else scf_status = opx_sccerror(status, &sqlstate, error, msg_buffer, (i4)msg_buf_length); if (scf_status != E_DB_OK) { TRdisplay( "Optimizer error = %x Status = %x Facility error = %x \n", error , status, facility); } } if (!facility) return; /* if facility error exists then ** report it in the same way */ ule_status = ule_format( facility, (CL_SYS_ERR *)NULL, log, &sqlstate, msg_buffer, (i4) (sizeof(msg_buffer)-1), &msg_buf_length, &ule_error, 0); if (ule_status != E_DB_OK) { (VOID)STprintf(msg_buffer, "ULE error = %x\nOptimizer error = %x Status = %x Facility error cannot be found - error no = %x \n", ule_error, error , status, facility); } else msg_buffer[msg_buf_length] = 0; /* null terminate */ { DB_STATUS scf1_status; scf1_status = opx_sccerror(status, &sqlstate, facility, msg_buffer, (i4)msg_buf_length); if (scf1_status != E_DB_OK) { TRdisplay( "Optimizer error = %x Status = %x Facility error = %x \n", error , status, facility); } } }
/*{ ** Name: dmv_unbtree_del - UNDO of a delete key operation. ** ** Description: ** This function removes a key from a btree index for the recovery of a ** delete record operation. ** ** Inputs: ** dmve Pointer to dmve control block. ** tabio Pointer to table io control block ** page Pointer to page on which row was insert ** ** Outputs: ** error Pointer to Error return area ** Returns: ** E_DB_OK ** E_DB_ERROR ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 14-dec-1992 (rogerk) ** Written for 6.5 recovery. ** 18-jan-1992 (rogerk) ** Add check in undo routine for case when null page pointer is ** passed because undo was found to be not needed. ** 15-mar-1993 (jnash) ** Check dmve->dmve_logging to determine if logging required. ** 26-apr-1993 (bryanp) ** 6.5 Cluster support: ** Replace all uses of DM_LOG_ADDR with LG_LA or LG_LSN. ** 15-apr-1994 (chiku) ** Bug56702: return logfull indication. ** 06-may-1996 (thaju02 & nanpr01) ** New page format support: change page header references to ** use macros. ** 22-nov-96 (stial01,dilma04) ** Row Locking Project: ** Allocate space only if space reclaimed ** 27-feb-97 (stial01) ** dmv_unbtree_del() allocate parameter TRUE If dm1cxallocate needed ** Log key in CLR, needed for row locking ** 21-may-1997 (stial01) ** Added flags arg to dm0p_unmutex call(s). */ static DB_STATUS dmv_unbtree_del( DMVE_CB *dmve, DMP_TABLE_IO *tabio, DMP_PINFO *pinfo, DM_TID *bid, bool allocate) { DM0L_BTDEL *log_rec = (DM0L_BTDEL *)dmve->dmve_log_rec; DB_STATUS status = E_DB_OK; DM_LINE_IDX childkey; DM_LINE_IDX childtid; LG_LSN lsn; DM_TID temptid; i4 temppartno; i4 page_type = log_rec->btd_pg_type; i4 ix_compressed; char *key; i4 flags; i4 loc_id; i4 loc_config_id; bool index_update; i4 update_mode; i4 local_err; i4 *err_code = &dmve->dmve_error.err_code; LG_LRI lri; DMPP_PAGE *page = pinfo->page; CLRDBERR(&dmve->dmve_error); /* ** If there is nothing to recover, just return. */ if (page == NULL) return (E_DB_OK); key = &log_rec->btd_vbuf[0]; index_update = ((DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & DMPP_INDEX) != 0); ix_compressed = DM1CX_UNCOMPRESSED; if (log_rec->btd_cmp_type != TCB_C_NONE) ix_compressed = DM1CX_COMPRESSED; /* ** Get information on the location to which the update is being made. */ loc_id = DM2F_LOCID_MACRO(tabio->tbio_loc_count, (i4) DM1B_VPT_GET_PAGE_PAGE_MACRO(page_type, page)); loc_config_id = tabio->tbio_location_array[loc_id].loc_config_id; /* ** Deletes to non-leaf index pages actually effect more than one entry ** on the page. The logged bid describes the entry from which the ** TID pointer is deleted. The key entry is deleted from the previous ** position (if there is one). */ if (index_update) { childtid = log_rec->btd_bid_child; childkey = log_rec->btd_bid_child; } else { childtid = bid->tid_tid.tid_line; childkey = bid->tid_tid.tid_line; } /* Index pages do not contain partition numbers */ temppartno = 0; if (index_update && (childkey != 0)) { childkey--; dm1cxtget(page_type, log_rec->btd_page_size, page, childkey, &temptid, &temppartno); } /* ** It would be nice to verify that the child position logged (or calculated ** by recovery) is the correct spot in the table, but since we have ** no attribute or key information to go on, we cannot do key comparisons. ** We must trust that the values are correct. ** ** We assume here that there is sufficient space on the page. If not, ** then the dm1cx calls below will catch the error. ** Since we will have backed out any inserts to this page that may have ** occurred after the delete, we should be assured that the the row will ** still fit. If it doesn't, then a fatal recovery error will occur. */ /* ** Mutex the page. This must be done prior to the log write. */ dmveMutex(dmve, pinfo); /* ** Check direction of recovery operation: ** ** If this is a normal Undo, then we log the CLR for the operation ** and write the LSN of this CLR onto the newly updated page (unless ** dmve_logging is turned off - in which case the rollback is not ** logged and the page lsn is unchanged). ** ** If the record being processed is itself a CLR, then we are REDOing ** an update made during rollback processing. Updates are not relogged ** in redo processing and the LSN is moved forward to the LSN value of ** of the original update. ** ** As of release OpenIngres 2.0, we need the key value in CLRs as well, ** because of row locking. */ if ((log_rec->btd_header.flags & DM0L_CLR) == 0) { if (dmve->dmve_logging) { flags = (log_rec->btd_header.flags | DM0L_CLR); /* Extract previous page change info */ DM1B_VPT_GET_PAGE_LRI_MACRO(log_rec->btd_pg_type, page, &lri); status = dm0l_btdel(dmve->dmve_log_id, flags, &log_rec->btd_tbl_id, tabio->tbio_relid, 0, tabio->tbio_relowner, 0, log_rec->btd_pg_type, log_rec->btd_page_size, log_rec->btd_cmp_type, log_rec->btd_loc_cnt, loc_config_id, bid, childkey, &log_rec->btd_tid, log_rec->btd_key_size, key, &log_rec->btd_header.lsn, &lri, log_rec->btd_partno, log_rec->btd_btflags, &dmve->dmve_error); if (status != E_DB_OK) { dmveUnMutex(dmve, pinfo); /* * Bug56702: return logfull indication. */ dmve->dmve_logfull = dmve->dmve_error.err_code; uleFormat(&dmve->dmve_error, 0, (CL_ERR_DESC *)NULL, ULE_LOG, NULL, (char *)NULL, (i4)0, (i4 *)NULL, &local_err, 0); SETDBERR(&dmve->dmve_error, 0, E_DM9652_UNDO_BTREE_DEL); return(E_DB_ERROR); } } } else { /* ** If we are processing recovery of an Insert CLR (redo-ing the undo ** of an insert) then we don't log a CLR but instead save the LSN ** of the log record we are processing with which to update the ** page lsn's. */ DM0L_MAKE_LRI_FROM_LOG_RECORD(&lri, log_rec); } /* ** Write the LSN, etc, of the delete record onto the page, unless nologging */ if (dmve->dmve_logging) DM1B_VPT_SET_PAGE_LRI_MACRO(page_type, page, &lri); update_mode = DM1C_DIRECT; if ((dmve->dmve_lk_type == LK_ROW || dmve->dmve_lk_type == LK_CROW) || (!index_update && log_rec->btd_pg_type != TCB_PG_V1 && dmve->dmve_lk_type == LK_PAGE && (log_rec->btd_header.flags & DM0L_PHYS_LOCK))) update_mode |= DM1C_ROWLK; /* ** Undo the delete operation. */ for (;;) { /* ** Allocate space if necessary */ if ( allocate == TRUE ) { status = dm1cxallocate(page_type, log_rec->btd_page_size, page, update_mode, ix_compressed, &dmve->dmve_tran_id, (i4)0, childkey, log_rec->btd_key_size + DM1B_VPT_GET_BT_TIDSZ_MACRO( page_type, page)); if (status != E_DB_OK) { dm1cxlog_error(E_DM93E0_BAD_INDEX_ALLOC, (DMP_RCB *)NULL, page, page_type, log_rec->btd_page_size, childkey); break; } } /* ** Reinsert the key,tid,partition values. */ /* If leaf overflow look for entry with matching tid */ /* skip key comparison all the keys on overflow are the same */ if (DM1B_VPT_GET_PAGE_STAT_MACRO(page_type, page) & DMPP_CHAIN) { i4 i; DM_TID tmptid; i4 tmppart; LG_LSN lsn; for (i = 0; i < DM1B_VPT_GET_BT_KIDS_MACRO(page_type, page); i++) { dm1cxtget(page_type, log_rec->btd_page_size, page, i, &tmptid, &tmppart); lsn = DMPP_VPT_GET_PAGE_LSN_MACRO(page_type, page); if (log_rec->btd_tid.tid_i4 == tmptid.tid_i4 && dmpp_vpt_test_free_macro(page_type, DM1B_VPT_BT_SEQUENCE_MACRO(page_type, page), (i4)i + DM1B_OFFSEQ) == FALSE) TRdisplay("dmvebtdl: dup entry on overflow %d for tid %d,%d CRPAGE %d page lsn %x\n", DM1B_VPT_GET_PAGE_PAGE_MACRO(page_type, page), log_rec->btd_tid.tid_tid.tid_page, log_rec->btd_tid.tid_tid.tid_line, DMPP_VPT_IS_CR_PAGE(page_type, page), lsn.lsn_low); /* does this trigger the dm1bxreserve failure from dm1bxovfl_alloc return (E_DB_ERROR); */ } } status = dm1cxput(page_type, log_rec->btd_page_size, page, ix_compressed, update_mode, &dmve->dmve_tran_id, LOG_ID_ID(dmve->dmve_log_id), (i4)0, childkey, key, log_rec->btd_key_size, &log_rec->btd_tid, log_rec->btd_partno); if (status != E_DB_OK) { dm1cxlog_error(E_DM93E4_BAD_INDEX_PUT, (DMP_RCB *)NULL, page, page_type, log_rec->btd_page_size, childkey); break; } /* ** If the insert is to a non-leaf index page, then the logged tid ** value must actually be insert to the position after the one ** to which we just put the key. Replace the old tidp from that ** position and insert the new one to the next entry. */ if (index_update && (childkey != childtid)) { status = dm1cxtput(page_type, log_rec->btd_page_size, page, childtid, &log_rec->btd_tid, log_rec->btd_partno); if (status != E_DB_OK) { dm1cxlog_error(E_DM93EB_BAD_INDEX_TPUT, (DMP_RCB *)NULL, page, page_type, log_rec->btd_page_size, childtid); break; } status = dm1cxtput(page_type, log_rec->btd_page_size, page, childkey, &temptid, temppartno); if (status != E_DB_OK) { dm1cxlog_error(E_DM93EB_BAD_INDEX_TPUT, (DMP_RCB *)NULL, page, page_type, log_rec->btd_page_size, childkey); break; } } break; } DM1B_VPT_SET_PAGE_STAT_MACRO(page_type, page, DMPP_MODIFY); dmveUnMutex(dmve, pinfo); if (status != E_DB_OK) { SETDBERR(&dmve->dmve_error, 0, E_DM9652_UNDO_BTREE_DEL); return(E_DB_ERROR); } return(E_DB_OK); }
/*{ ** Name: DI_slave_read - Request a slave to read page(s) from a file on disk. ** ** Description: ** This routine was created to make DIread more readable once ** error checking had been added. See DIread for comments. ** ** Inputs: ** f Pointer to the DI file ** context needed to do I/O. ** diop Pointer to dilru file context. ** buf Pointer to page(s) to read. ** page Value indicating page(s) to read. ** num_of_pages number of pages to read. ** ** Outputs: ** err_code Pointer to a variable used ** to return operating system ** errors. ** Returns: ** OK ** other errors. ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 30-nov-1992 (rmuth) ** Created. ** 10-mar-1993 (mikem) ** Changed the type of the first parameter to DI_send_ev_to_slave() and ** the 2nd parameter to DI_slave_send(), so that DI_send_ev_to_slave() ** could access the slave control block's status. ** This routine will now initialize the status to DI_INPROGRESS, before ** making the request and the slave will change the status once the ** operation is complete. ** 23-aug-1993 (bryanp) ** If memory segment isn't yet mapped, map it. */ static STATUS DI_slave_read( DI_IO *f, DI_OP *diop, char *buf, i4 page, i4 num_of_pages, i4 *n, CL_ERR_DESC *err_code) { register DI_SLAVE_CB *disl; ME_SEG_INFO *seginfo; bool direct_read; STATUS small_status = OK, big_status = OK, intern_status = OK, status; /* unix variables */ int bytes_to_read; int bytes_read = 0; do { disl = diop->di_evcb; disl->pre_seek = (OFFSET_TYPE)(f->io_bytes_per_page) * (OFFSET_TYPE)(page); bytes_to_read = f->io_bytes_per_page * num_of_pages; /* ** determine whether we're reading into shared memory, and set ** up the segment ID and offset correctly */ seginfo = ME_find_seg( buf, (char *)buf + bytes_to_read, &ME_segpool); if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) == 0) { status = DI_lru_slmapmem(seginfo, &intern_status, &small_status); if (status) break; } if (seginfo != 0 && (seginfo->flags & ME_SLAVEMAPPED_MASK) != 0) { MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset = (char *)buf - (char *)seginfo->addr; direct_read = TRUE; } else { direct_read = FALSE; seginfo = ME_find_seg(disl->buf, disl->buf, &ME_segpool); if (seginfo) { MEcopy( (PTR)seginfo->key, sizeof(disl->seg_key), (PTR)disl->seg_key); disl->seg_offset= (char *)disl->buf - (char *)seginfo->addr; } else { small_status = DI_BADREAD; break; } } /* ** seek to place to read */ do { disl->file_op = DI_SL_READ; /* Send file properties to slave */ FPROP_COPY(f->io_fprop,disl->io_fprop); if (direct_read) disl->length = bytes_to_read; else disl->length = min(bytes_to_read, Cs_srv_block.cs_size_io_buf); DI_slave_send( disl->dest_slave_no, diop, &big_status, &small_status, &intern_status); if (( big_status != OK ) || ( small_status != OK )) break; if ((small_status = disl->status) != OK ) { STRUCT_ASSIGN_MACRO(disl->errcode, *err_code); small_status = DI_BADREAD; break; } else { if ( disl->length == 0 ) { small_status = DI_ENDFILE; #ifdef xDEV_TST TRdisplay("num_pages %d\n, read_op = %x", num_of_pages, 0x70000000); DIlru_dump(); #endif /* xDev_TST */ break; } } /* ** Read data ok */ if (! direct_read) { MEcopy((PTR)disl->buf, disl->length, (PTR)buf); buf += disl->length; } bytes_to_read -= disl->length; disl->pre_seek += (OFFSET_TYPE)disl->length; bytes_read += disl->length; } while ( bytes_to_read > 0); } while (FALSE); if ( bytes_read > 0 ) *n = bytes_read / f->io_bytes_per_page; if ( big_status != OK ) small_status = big_status; if (small_status != OK ) DIlru_set_di_error( &small_status, err_code, intern_status, DI_GENERAL_ERR); return(small_status); }
/*{ ** ** 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); }