/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockAcquire( F_RWLOCK hReadWriteLock, F_SEM hSem, FLMBOOL bWriter) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; FLMBOOL bMutexLocked = FALSE; f_mutexLock( pReadWriteLock->hMutex); bMutexLocked = TRUE; if( bWriter) { if( pReadWriteLock->iRefCnt != 0) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter), &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { f_assert( !pReadWriteLock->iRefCnt); pReadWriteLock->iRefCnt = -1; pReadWriteLock->uiWriteThread = f_threadId(); } } else { if( pReadWriteLock->iRefCnt < 0 || pReadWriteLock->pNotifyList) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)((FLMINT)bWriter), &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { pReadWriteLock->iRefCnt++; } } f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); if( bMutexLocked) { f_mutexUnlock( pReadWriteLock->hMutex); } return( rc); }
/**************************************************************************** Desc: Ends a logging message ****************************************************************************/ void flmEndLogMessage( IF_LogMessageClient ** ppLogMessage) { if( *ppLogMessage) { f_mutexLock( gv_XFlmSysData.hLoggerMutex); flmAssert( gv_XFlmSysData.uiPendingLogMessages); (*ppLogMessage)->endMessage(); (*ppLogMessage)->Release(); *ppLogMessage = NULL; gv_XFlmSysData.uiPendingLogMessages--; f_mutexUnlock( gv_XFlmSysData.hLoggerMutex); } }
/**************************************************************************** Desc: ****************************************************************************/ void FTKAPI F_IOBuffer::clearPending( void) { f_assert( m_bPending); if( m_pBufferMgr) { f_assert( m_eList == MGR_LIST_PENDING); f_mutexLock( m_pBufferMgr->m_hMutex); m_pBufferMgr->unlinkFromList( this); m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstUsed, this); f_mutexUnlock( m_pBufferMgr->m_hMutex); } m_bPending = FALSE; m_uiStartTime = 0; }
/******************************************************************** Desc: Output a string in the DATA_COLUMN *********************************************************************/ void gigaOutputStr( FLMUINT uiRow, const char * pszStr, FLMBOOL bMutexLocked) { if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexLock( gv_hWindowMutex); } FTXWinPrintStrXY( gv_pWindow, pszStr, DATA_COLUMN, uiRow); if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexUnlock( gv_hWindowMutex); } }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogUpdate( F_Database * pDatabase, FLMUINT64 ui64TransId, FLMUINT uiCollection, FLMUINT64 ui64NodeId, RCODE rc, char * pszEvent) { char pszTmpBuf[ 256]; char szErr [12]; if (!g_bDbgLogEnabled) { return; } if (RC_BAD( rc)) { f_sprintf( szErr, " RC=%04X", (unsigned)rc); } else { szErr [0] = 0; } if (uiCollection) { f_sprintf( (char *)pszTmpBuf, "d%X t%I64u c%u n%I64u %s%s", (unsigned)((FLMUINT)pDatabase), ui64TransId, (unsigned)uiCollection, ui64NodeId, pszEvent, szErr); } else { f_sprintf( (char *)pszTmpBuf, "d%X t%I64u %s%s", (unsigned)((FLMUINT)pDatabase), ui64TransId, pszEvent, szErr); } f_mutexLock( g_hDbgLogMutex); _flmDbgOutputMsg( pszTmpBuf); f_mutexUnlock( g_hDbgLogMutex); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockPromote( F_RWLOCK hReadWriteLock, F_SEM hSem) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; FLMBOOL bMutexLocked = FALSE; f_mutexLock( pReadWriteLock->hMutex); bMutexLocked = TRUE; if( pReadWriteLock->iRefCnt <= 0) { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } pReadWriteLock->iRefCnt--; if( pReadWriteLock->iRefCnt != 0) { rc = f_notifyWait( pReadWriteLock->hMutex, hSem, (void *)TRUE, &pReadWriteLock->pNotifyList); } if( RC_OK( rc)) { f_assert( !pReadWriteLock->iRefCnt); pReadWriteLock->iRefCnt = -1; pReadWriteLock->uiWriteThread = f_threadId(); } Exit: f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); if( bMutexLocked) { f_mutexUnlock( pReadWriteLock->hMutex); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockRelease( F_RWLOCK hReadWriteLock) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; FLMBOOL bMutexLocked = FALSE; f_mutexLock( pReadWriteLock->hMutex); bMutexLocked = TRUE; if( pReadWriteLock->iRefCnt > 0) { pReadWriteLock->iRefCnt--; } else if( pReadWriteLock->iRefCnt == -1) { f_assert( pReadWriteLock->uiWriteThread == f_threadId()); pReadWriteLock->iRefCnt = 0; } else { rc = RC_SET_AND_ASSERT( NE_FLM_ILLEGAL_OP); goto Exit; } if( !pReadWriteLock->iRefCnt && pReadWriteLock->pNotifyList) { f_rwlockNotify( pReadWriteLock); } Exit: f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt >= 0); if( bMutexLocked) { f_mutexUnlock( pReadWriteLock->hMutex); } return( rc); }
/******************************************************************** Desc: *********************************************************************/ void gigaUpdateLoadTimes( void) { FLMUINT uiElapsedTime; FLMUINT uiCurrTime; FLMUINT uiSecs; FLMUINT uiAddsPerSec; char szElapsedTime [20]; uiCurrTime = FLM_GET_TIMER(); uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime, gv_ui10SecStartTime); // Calculate and display the average for the last 10 seconds. uiSecs = FLM_TIMER_UNITS_TO_SECS( uiElapsedTime); uiAddsPerSec = (gv_uiTotalLoaded - gv_ui10SecTotal) / uiSecs; f_mutexLock( gv_hWindowMutex); gigaOutputUINT( ADDS_PER_SEC_CURRENT, uiAddsPerSec, TRUE); gv_ui10SecTotal = gv_uiTotalLoaded; gv_ui10SecStartTime = uiCurrTime; // Calculate and display the overall average uiElapsedTime = FLM_ELAPSED_TIME( uiCurrTime, gv_uiStartTime); uiSecs = FLM_TIMER_UNITS_TO_SECS( uiElapsedTime); uiAddsPerSec = gv_uiTotalLoaded / uiSecs; gigaOutputUINT( ADDS_PER_SEC_OVERALL, uiAddsPerSec, TRUE); f_sprintf( szElapsedTime, "%u:%02u:%02u", (unsigned)uiSecs / 3600, (unsigned)(uiSecs % 3600) / 60, (unsigned)uiSecs % 60); gigaOutputStr( ELAPSED_TIME_ROW, szElapsedTime, TRUE); f_mutexUnlock( gv_hWindowMutex); }
/**************************************************************************** Desc: Returns an IF_LogMessageClient object if logging is enabled for the specified message type ****************************************************************************/ IF_LogMessageClient * flmBeginLogMessage( eLogMessageType eMsgType) { IF_LogMessageClient * pNewMsg = NULL; f_mutexLock( gv_XFlmSysData.hLoggerMutex); if( !gv_XFlmSysData.pLogger) { goto Exit; } if( (pNewMsg = gv_XFlmSysData.pLogger->beginMessage( eMsgType)) != NULL) { gv_XFlmSysData.uiPendingLogMessages++; } Exit: f_mutexUnlock( gv_XFlmSysData.hLoggerMutex); return( pNewMsg); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FLMAPI f_rwlockTryAcquire( F_RWLOCK hReadWriteLock, FLMBOOL bWriter) { RCODE rc = NE_FLM_OK; F_RWLOCK_IMP * pReadWriteLock = (F_RWLOCK_IMP *)hReadWriteLock; f_mutexLock( pReadWriteLock->hMutex); if( bWriter) { if( pReadWriteLock->iRefCnt != 0) { rc = RC_SET( NE_FLM_WAIT_TIMEOUT); } else { pReadWriteLock->iRefCnt = -1; pReadWriteLock->uiWriteThread = f_threadId(); } } else { if( pReadWriteLock->iRefCnt < 0 || pReadWriteLock->pNotifyList) { rc = RC_SET( NE_FLM_WAIT_TIMEOUT); } else { pReadWriteLock->iRefCnt++; } } f_assert( RC_BAD( rc) || pReadWriteLock->iRefCnt); f_mutexUnlock( pReadWriteLock->hMutex); return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void FTKAPI F_IOBuffer::setPending( void) { f_assert( !m_bPending); if( m_pBufferMgr) { f_assert( m_eList == MGR_LIST_USED); f_mutexLock( m_pBufferMgr->m_hMutex); m_pBufferMgr->unlinkFromList( this); m_pBufferMgr->linkToList( &m_pBufferMgr->m_pFirstPending, this); f_mutexUnlock( m_pBufferMgr->m_hMutex); } #ifndef FLM_UNIX f_assert( !m_pAsyncClient || f_semGetSignalCount( ((F_FileAsyncClient *)m_pAsyncClient)->m_hSem) == 0); #endif m_bPending = TRUE; m_uiStartTime = FLM_GET_TIMER(); m_uiEndTime = 0; }
/**************************************************************************** Desc: Make sure a database is NOT open. If it is, return an error. ****************************************************************************/ RCODE F_DbSystem::checkDatabaseClosed( const char * pszDbName, const char * pszDataDir) { RCODE rc = NE_XFLM_OK; F_Database * pDatabase; f_mutexLock( gv_XFlmSysData.hShareMutex); rc = findDatabase( pszDbName, pszDataDir, &pDatabase); f_mutexUnlock( gv_XFlmSysData.hShareMutex); if (RC_BAD( rc)) { goto Exit; } if (pDatabase) { rc = RC_SET( NE_XFLM_DATABASE_OPEN); goto Exit; } Exit: return( rc); }
/**************************************************************************** Desc: This routine starts a transaction for the specified database. The transaction may be part of an overall larger transaction. ****************************************************************************/ RCODE flmBeginDbTrans( FDB * pDb, FLMUINT uiTransType, FLMUINT uiMaxLockWait, FLMUINT uiFlags, FLMBYTE * pucLogHdr) { RCODE rc = FERR_OK; FFILE * pFile = pDb->pFile; FLMBOOL bMutexLocked = FALSE; FLMBYTE * pucLastCommittedLogHdr; DB_STATS * pDbStats = pDb->pDbStats; if( RC_BAD( rc = flmCheckDatabaseState( pDb))) { goto Exit; } // Initialize a few things - as few as is necessary to avoid // unnecessary overhead. pDb->eAbortFuncId = FLM_UNKNOWN_FUNC; pDb->AbortRc = FERR_OK; pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0]; pDb->KrefCntrl.bKrefSetup = FALSE; pDb->uiTransType = uiTransType; pDb->uiThreadId = (FLMUINT)f_threadId(); pDb->uiTransCount++; // Link the FDB to the file's most current FDICT structure, // if there is one. // // Also, if it is a read transaction, link the FDB // into the list of read transactions off of // the FFILE structure. f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; if (pFile->pDictList) { // Link the FDB to the FDICT. flmLinkFdbToDict( pDb, pFile->pDictList); } // If it is a read transaction, link into the list of // read transactions off of the FFILE structure. Until we // get the log header transaction ID below, we set uiCurrTransID // to zero and link this transaction in at the beginning of the // list. if (uiTransType == FLM_READ_TRANS) { flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); // Link in at the end of the transaction list. pDb->pNextReadTrans = NULL; if ((pDb->pPrevReadTrans = pFile->pLastReadTrans) != NULL) { // Make sure transaction IDs are always in ascending order. They // should be at this point. flmAssert( pFile->pLastReadTrans->LogHdr.uiCurrTransID <= pDb->LogHdr.uiCurrTransID); pFile->pLastReadTrans->pNextReadTrans = pDb; } else { pFile->pFirstReadTrans = pDb; } pFile->pLastReadTrans = pDb; pDb->uiInactiveTime = 0; if( uiFlags & FLM_DONT_KILL_TRANS) { pDb->uiFlags |= FDB_DONT_KILL_TRANS; } else { pDb->uiFlags &= ~FDB_DONT_KILL_TRANS; } if (pucLogHdr) { f_memcpy( pucLogHdr, &pDb->pFile->ucLastCommittedLogHdr[0], LOG_HEADER_SIZE); } } f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; if( uiFlags & FLM_DONT_POISON_CACHE) { pDb->uiFlags |= FDB_DONT_POISON_CACHE; } else { pDb->uiFlags &= ~FDB_DONT_POISON_CACHE; } // Put an exclusive lock on the database if we are not in a read // transaction. Read transactions require no lock. if (uiTransType != FLM_READ_TRANS) { flmAssert( pDb->pIxStats == NULL); // Set the bHadUpdOper to TRUE for all transactions to begin with. // Many calls to flmBeginDbTrans are internal, and we WANT the // normal behavior at the end of the transaction when it is // committed or aborted. The only time this flag will be set // to FALSE is when the application starts the transaction as // opposed to an internal starting of the transaction. pDb->bHadUpdOper = TRUE; // Initialize the count of blocks changed to be 0 pDb->uiBlkChangeCnt = 0; if (RC_BAD( rc = dbLock( pDb, uiMaxLockWait))) { goto Exit; } // If there was a problem with the RFL volume, we must wait // for a checkpoint to be completed before continuing. // The checkpoint thread looks at this same flag and forces // a checkpoint. If it completes one successfully, it will // reset this flag. // // Also, if the last forced checkpoint had a problem // (pFile->CheckpointRc != FERR_OK), we don't want to // start up a new update transaction until it is resolved. if (!pFile->pRfl->seeIfRflVolumeOk() || RC_BAD( pFile->CheckpointRc)) { rc = RC_SET( FERR_MUST_WAIT_CHECKPOINT); goto Exit; } // Set the first log block address to zero. pFile->uiFirstLogBlkAddress = 0; // Header must be read before opening roll forward log file to make // sure we have the most current log file and log options. f_memcpy( pFile->ucUncommittedLogHdr, pucLastCommittedLogHdr, LOG_HEADER_SIZE); flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); // Need to increment the current checkpoint for update transactions // so that it will be correct when we go to mark cache blocks. if (pDb->uiFlags & FDB_REPLAYING_RFL) { // During recovery we need to set the transaction ID to the // transaction ID that was logged. pDb->LogHdr.uiCurrTransID = pFile->pRfl->getCurrTransID(); } else { pDb->LogHdr.uiCurrTransID++; } f_mutexLock( gv_FlmSysData.hShareMutex); // Link FDB to the most current local dictionary, if there // is one. if (pFile->pDictList != pDb->pDict && pFile->pDictList) { flmLinkFdbToDict( pDb, pFile->pDictList); } pFile->uiUpdateTransID = pDb->LogHdr.uiCurrTransID; f_mutexUnlock( gv_FlmSysData.hShareMutex); // Set the transaction EOF to the current file EOF pDb->uiTransEOF = pDb->LogHdr.uiLogicalEOF; // Put the transaction ID into the uncommitted log header. UD2FBA( (FLMUINT32)pDb->LogHdr.uiCurrTransID, &pFile->ucUncommittedLogHdr [LOG_CURR_TRANS_ID]); if (pucLogHdr) { f_memcpy( pucLogHdr, &pDb->pFile->ucUncommittedLogHdr [0], LOG_HEADER_SIZE); } } if (pDbStats) { f_timeGetTimeStamp( &pDb->TransStartTime); } // If we do not have a dictionary, read it in from disk. // NOTE: This should only happen when we are first opening // the database. if (!pDb->pDict) { flmAssert( pDb->pFile->uiFlags & DBF_BEING_OPENED); if (RC_BAD( rc = fdictRebuild( pDb))) { if (pDb->pDict) { flmFreeDict( pDb->pDict); pDb->pDict = NULL; } goto Exit; } f_mutexLock( gv_FlmSysData.hShareMutex); // At this point, we will not yet have opened the database for // general use, so there is no way that any other thread can have // created a dictionary yet. flmAssert( pDb->pFile->pDictList == NULL); // Link the new local dictionary to its file structure. flmLinkDictToFile( pDb->pFile, pDb->pDict); f_mutexUnlock( gv_FlmSysData.hShareMutex); } Exit: if( bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } if (uiTransType != FLM_READ_TRANS) { if (RC_OK( rc)) { rc = pFile->pRfl->logBeginTransaction( pDb); } #ifdef FLM_DBG_LOG flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, 0, 0, rc, "TBeg"); #endif } if( uiTransType == FLM_UPDATE_TRANS && gv_FlmSysData.UpdateEvents.pEventCBList) { flmTransEventCallback( F_EVENT_BEGIN_TRANS, (HFDB)pDb, rc, (FLMUINT)(RC_OK( rc) ? pDb->LogHdr.uiCurrTransID : (FLMUINT)0)); } if (RC_BAD( rc)) { // If there was an error, unlink the database from the transaction // structure as well as from the FDICT structure. flmUnlinkDbFromTrans( pDb, FALSE); if (pDb->pStats) { (void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats); } } return( rc); }
/**************************************************************************** Desc: Stops a background indexing thread Notes: This routine DOES NOT assume that the global mutex is locked. It will lock and unlock the mutex as needed. ****************************************************************************/ FSTATIC void stopBackgroundIndexThread( FDB * pDb, FLMUINT uiIndexNum, FLMBOOL bWait, FLMBOOL * pbStopped) { F_BKGND_IX * pBackgroundIx; FLMUINT uiThreadId; FLMBOOL bMutexLocked = FALSE; if( pbStopped) { *pbStopped = FALSE; } for( ;;) { // Lock the global mutex if( !bMutexLocked) { f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; } // Get the background index if( (pBackgroundIx = flmBackgroundIndexGet( pDb->pFile, uiIndexNum, TRUE, &uiThreadId)) == NULL) { if( pbStopped) { *pbStopped = TRUE; } goto Exit; } // Set the thread's shutdown flag first. gv_FlmSysData.pThreadMgr->setThreadShutdownFlag( uiThreadId); // Unlock the global mutex f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; // The thread may be waiting to start a transaction. pDb->pFile->pFileLockObj->timeoutLockWaiter( uiThreadId); pDb->pFile->pWriteLockObj->timeoutLockWaiter( uiThreadId); if( !bWait) { break; } // Wait for the thread to terminate f_sleep( 50); } Exit: if( bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } }
/**************************************************************************** Desc : Return the status of the index. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexStatus( HFDB hDb, FLMUINT uiIndexNum, FINDEX_STATUS * pIndexStatus) { RCODE rc = FERR_OK; FLMBOOL bStartedAutoTrans = FALSE; FLMUINT uiLastDrnIndexed; FDB * pDb = (FDB *)hDb; F_BKGND_IX * pBackgroundIx; FLMBOOL bSuspended; FLMBOOL bMutexLocked = FALSE; flmAssert( pIndexStatus != NULL); if( IsInCSMode( hDb)) { fdbInitCS( pDb); rc = flmIndexStatusCS( pDb, uiIndexNum, pIndexStatus); goto Exit; } if( RC_BAD( rc = fdbInit( (FDB *)hDb, FLM_READ_TRANS, FDB_TRANS_GOING_OK, 0, &bStartedAutoTrans))) { goto Exit; } f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; pBackgroundIx = flmBackgroundIndexGet( pDb->pFile, uiIndexNum, TRUE); if( pBackgroundIx) { f_memcpy( pIndexStatus, &pBackgroundIx->indexStatus, sizeof( FINDEX_STATUS)); f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; flmAssert( pIndexStatus->uiIndexNum == uiIndexNum); } else { IXD * pIxd; FLMBOOL bTrackerIxSuspended; if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, uiIndexNum,NULL, &pIxd, TRUE))) { goto Exit; } bSuspended = (pIxd->uiFlags & IXD_SUSPENDED) ? TRUE : FALSE; f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; // Get the index state from the tracker if( RC_BAD( rc = flmGetIxTrackerInfo( pDb, uiIndexNum, NULL, &uiLastDrnIndexed, NULL, &bTrackerIxSuspended))) { if( rc == FERR_NOT_FOUND) { rc = RC_SET( FERR_BAD_IX); } goto Exit; } // Sanity check #ifdef FLM_DEBUG if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_51 && bSuspended != bTrackerIxSuspended) { flmAssert( 0); } #endif // Populate the index status structure. f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS)); pIndexStatus->uiIndexNum = uiIndexNum; pIndexStatus->uiLastRecordIdIndexed = uiLastDrnIndexed; pIndexStatus->bSuspended = bSuspended; } Exit: if( bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } if( bStartedAutoTrans) { rc = flmEndAutoTrans( pDb, rc); } flmExit( FLM_INDEX_STATUS, pDb, rc); return( rc); }
/**************************************************************************** Desc: Looks for a background indexing thread that is running with a matching action and value. Note: The shared semaphore must be locked on the outside while calling this routine and accessing anything within the F_BKGND_IX structure. ****************************************************************************/ F_BKGND_IX * flmBackgroundIndexGet( FFILE * pFile, FLMUINT uiIndexNum, FLMBOOL bMutexLocked, FLMUINT * puiThreadId) { RCODE rc = FERR_OK; IF_Thread * pThread; FLMUINT uiThreadId; F_BKGND_IX * pBackgroundIx = NULL; if( !bMutexLocked) { f_mutexLock( gv_FlmSysData.hShareMutex); } uiThreadId = 0; for( ;;) { if( RC_BAD( rc = gv_FlmSysData.pThreadMgr->getNextGroupThread( &pThread, gv_uiBackIxThrdGroup, &uiThreadId))) { if( rc == FERR_NOT_FOUND) { rc = FERR_OK; break; } else { flmAssert( 0); } } if( pThread->getThreadAppId()) { F_BKGND_IX * pTmpIx = NULL; pTmpIx = (F_BKGND_IX *)pThread->getParm1(); if( pTmpIx->indexStatus.uiIndexNum == uiIndexNum && pTmpIx->pFile == pFile) { flmAssert( pThread->getThreadAppId() == uiIndexNum); pBackgroundIx = pTmpIx; pThread->Release(); if( puiThreadId) { *puiThreadId = uiThreadId; } break; } } pThread->Release(); } if( !bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } return( pBackgroundIx); }
/**************************************************************************** Desc: Thread that will build an index in the background. Caller will create a pDb to use. This pDb must be freed at the conclusion of the routine. ****************************************************************************/ FSTATIC RCODE FLMAPI flmBackgroundIndexBuildThrd( IF_Thread * pThread) { RCODE rc = FERR_OK; IXD * pIxd; F_BKGND_IX * pBackgroundIx = (F_BKGND_IX *)pThread->getParm1(); FLMBOOL bStartedTrans; FLMBOOL bDbInitialized; FLMUINT uiContainerNum; FLMUINT uiFirstDrn; FLMUINT uiIndexNum; FDB * pDb = NULL; FLMBOOL bForcedShutdown = FALSE; FLMBOOL bHitEnd; FINDEX_STATUS savedIxStatus; FlmRecord * pReusableRec = NULL; char szMsg[ 128]; FLMINT iErrorLine = 0; FLMBOOL bLimitedMode = FALSE; pThread->setThreadStatus( FLM_THREAD_STATUS_INITIALIZING); if( (pReusableRec = f_new FlmRecord) != NULL) { if( RC_BAD( pReusableRec->preallocSpace( 512, 1024 * 64))) { pReusableRec->Release(); pReusableRec = NULL; } } Loop_Again: rc = FERR_OK; uiIndexNum = pBackgroundIx->indexStatus.uiIndexNum; flmAssert( pThread->getThreadAppId() == uiIndexNum); bDbInitialized = FALSE; bStartedTrans = FALSE; pDb = NULL; // We could loop forever on flmOpenFile errors, check if we should exit. if( pThread->getShutdownFlag()) { bForcedShutdown = TRUE; goto Exit; } if( RC_BAD( rc = flmOpenFile( pBackgroundIx->pFile, NULL, NULL, NULL, 0, TRUE, NULL, NULL, pBackgroundIx->pFile->pszDbPassword, &pDb))) { // If the file is being closed, this is not an error. if( pBackgroundIx->pFile->uiFlags & DBF_BEING_CLOSED) { bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } flmAssert( pDb->pSFileHdl); bDbInitialized = TRUE; if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, 0, 0, &bStartedTrans))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } flmAssert( !bStartedTrans); pDb->uiFlags |= FDB_BACKGROUND_INDEXING; for(;;) { // Set the thread's status pThread->setThreadStatus( FLM_THREAD_STATUS_RUNNING); // See if we should shut down. if( pThread->getShutdownFlag()) { bForcedShutdown = TRUE; break; } // Obtain the file lock flmAssert( !(pDb->uiFlags & FDB_HAS_FILE_LOCK)); if( RC_BAD( rc = pDb->pFile->pFileLockObj->lock( pDb->hWaitSem, TRUE, FLM_NO_TIMEOUT, FLM_BACKGROUND_LOCK_PRIORITY, pDb->pDbStats ? &pDb->pDbStats->LockStats : NULL))) { if( rc == FERR_IO_FILE_LOCK_ERR) { // This would only happen if we were signaled to shut down. // So, it's ok to exit flmAssert( pThread->getShutdownFlag()); bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } // The lock needs to be marked as implicit so that flmCommitDbTrans // will unlock the file and allow the next update transaction to // begin before all writes are complete. pDb->uiFlags |= (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); // If there are higher priority waiters in the lock queue, // or we are being told to shut down, we want to relinquish. if( pThread->getShutdownFlag() || pDb->pFile->pFileLockObj->haveHigherPriorityWaiter( FLM_BACKGROUND_LOCK_PRIORITY)) { if (RC_BAD( rc = pDb->pFile->pFileLockObj->unlock())) { iErrorLine = (FLMINT)__LINE__; goto Exit; } pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); continue; } // Start an update transaction if( RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, FLM_NO_TIMEOUT, FLM_DONT_POISON_CACHE))) { if( rc == FERR_IO_FILE_LOCK_ERR) { // This would only happen if we were signaled to shut down. // So, it's ok to exit flmAssert( pThread->getShutdownFlag()); bForcedShutdown = TRUE; rc = FERR_OK; } else { iErrorLine = (FLMINT)__LINE__; } goto Exit; } bStartedTrans = TRUE; if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, uiIndexNum, NULL, &pIxd, TRUE))) { // Index may have been deleted by another transaction, or // there may have been some other error. iErrorLine = (FLMINT)__LINE__; goto Exit; } // If we're running in limited mode, then we can't mess with encrypted // indexes. On the other hand, since the index is marked as offline, // but not suspended, this thread has to exist, or else it will cause // all kinds of problems elsewhere. So, in such a case, we will simply // sleep in an inifinite loop until the shutdown flag is set. // (We consider this acceptable becase running in limited mode is not // the norm, and Flaim probably won't be up for very long in this mode.) if( pDb->pFile->bInLimitedMode && pIxd->uiEncId) { bLimitedMode = TRUE; goto Exit; } // Look up the tracker info to determine where we need to being indexing if (RC_BAD( rc = flmGetIxTrackerInfo( pDb, pBackgroundIx->indexStatus.uiIndexNum, &uiContainerNum, &uiFirstDrn, NULL, &pBackgroundIx->indexStatus.bSuspended))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } // If the index is suspended, this thread should have been // shut down. The suspending thread will keep the database // locked until we exit. So, if we have the database locked, // the index better not be suspended. flmAssert( !pBackgroundIx->indexStatus.bSuspended && !(pIxd->uiFlags & IXD_SUSPENDED)); if (pIxd->uiContainerNum) { uiContainerNum = pIxd->uiContainerNum; if( uiFirstDrn == DRN_LAST_MARKER) { goto Exit; } } else { if( uiFirstDrn == DRN_LAST_MARKER && uiContainerNum == 0xFFFFFFFF) { goto Exit; } else { // The container number from the tracker record // may not be a real container. // Determine what the next actual container number is. if (uiContainerNum != FLM_DATA_CONTAINER) { while( uiContainerNum < pDb->pDict->uiIttCnt) { ITT * pItt = &pDb->pDict->pIttTbl [uiContainerNum]; if (ITT_IS_CONTAINER( pItt)) { break; } else { uiContainerNum++; } } if (uiContainerNum >= pDb->pDict->uiIttCnt) { uiContainerNum = FLM_DATA_CONTAINER; } } } } // Setup the DRN range we want to index. uiFirstDrn++; flmAssert( pIxd->uiLastDrnIndexed == uiFirstDrn - 1); // Set the thread's status pThread->setThreadStatus( "Indexing %u:%u", (unsigned)uiContainerNum, (unsigned)uiFirstDrn); // Read and index up to the highest drn (or record higher than uiEndDrn) // or until time runs out. The 500 is millisecs to take for the transaction. f_memcpy( &savedIxStatus, &pBackgroundIx->indexStatus, sizeof( FINDEX_STATUS)); if( RC_BAD( rc = flmIndexSetOfRecords( pDb, uiIndexNum, uiContainerNum, uiFirstDrn, DRN_LAST_MARKER, NULL, NULL, NULL, NULL, &pBackgroundIx->indexStatus, &bHitEnd, pThread, pReusableRec))) { // Lock the mutex while copying the saved index status back to // the main index status so that someone requesting the index status // won't see the status while the memcpy is in progress. f_mutexLock( gv_FlmSysData.hShareMutex); f_memcpy( &pBackgroundIx->indexStatus, &savedIxStatus, sizeof( FINDEX_STATUS)); f_mutexUnlock( gv_FlmSysData.hShareMutex); iErrorLine = (FLMINT)__LINE__; goto Exit; } if( pBackgroundIx->indexStatus.uiRecordsProcessed - savedIxStatus.uiRecordsProcessed) { if( RC_BAD( rc = pDb->pFile->pRfl->logIndexSet( uiIndexNum, uiContainerNum, uiFirstDrn, pBackgroundIx->indexStatus.uiLastRecordIdIndexed))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } } // Commit the transaction (even if we didn't do any indexing work). if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) { iErrorLine = (FLMINT)__LINE__; goto Exit; } bStartedTrans = FALSE; pBackgroundIx->indexStatus.uiTransactions++; if( bHitEnd) { // flmIndexSetOfRecords brought the index on-line if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIndexNum, (void *)0); } // Log a message flmLogIndexingProgress( uiIndexNum, 0); break; } } Exit: pThread->setThreadStatus( FLM_THREAD_STATUS_TERMINATING); if( bStartedTrans) { (void)flmAbortDbTrans( pDb); bStartedTrans = FALSE; } if( pDb && pDb->uiFlags & FDB_HAS_FILE_LOCK) { (void)pDb->pFile->pFileLockObj->unlock(); pDb->uiFlags &= ~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT); } if( bDbInitialized) { fdbExit( pDb); bDbInitialized = FALSE; } if( pDb) { (void)FlmDbClose( (HFDB *) &pDb); } if( RC_BAD(rc) && !bForcedShutdown) { if (rc == FERR_MEM || rc == FERR_IO_DISK_FULL || rc == FERR_MUST_WAIT_CHECKPOINT) { // Log the error f_sprintf( (char *)szMsg, "Background indexing thread %u (index %u)", (unsigned)pThread->getThreadId(), (unsigned)uiIndexNum); flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine); // Sleep a half second and try again. pThread->sleep( 500); goto Loop_Again; } else { f_sprintf( (char *)szMsg, "Background indexing thread %u (index %u) -- unrecoverable error.", (unsigned)pThread->getThreadId(), (unsigned)uiIndexNum); flmLogError( rc, (char *)szMsg, __FILE__, iErrorLine); } } if( pReusableRec) { flmAssert( pReusableRec->getRefCount() == 1); pReusableRec->Release(); } if( bLimitedMode) { flmAssert( RC_OK( rc)); for (;;) { if( pThread->getShutdownFlag()) { break; } pThread->sleep( 1000); } } // Set the thread's app ID to 0, so that it will not // be found now that the thread is terminating (we don't // want flmBackgroundIndexGet to find the thread). pThread->setThreadAppId( 0); // Free the background index structure f_mutexLock( gv_FlmSysData.hShareMutex); f_free( &pBackgroundIx); pThread->setParm1( NULL); f_mutexUnlock( gv_FlmSysData.hShareMutex); return( rc); }
/**************************************************************************** Desc: This routine aborts an active transaction for a particular database. If the database is open via a server, a message is sent to the server to abort the transaction. Otherwise, the transaction is rolled back locally. ****************************************************************************/ RCODE flmAbortDbTrans( FDB * pDb, FLMBOOL bOkToLogAbort) { RCODE rc = FERR_OK; FFILE * pFile = pDb->pFile; FLMUINT uiTransType; FLMBYTE * pucLastCommittedLogHdr; FLMBYTE * pucUncommittedLogHdr; FLMBOOL bDumpedCache = FALSE; DB_STATS * pDbStats = pDb->pDbStats; FLMBOOL bKeepAbortedTrans; FLMUINT uiTransId; FLMBOOL bInvisibleTrans; // Get transaction type if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS) { goto Exit; } // No recovery required if it is a read transaction. if (uiTransType == FLM_READ_TRANS) { if( pDb->KrefCntrl.bKrefSetup) { // KrefCntrlFree could be called w/o checking bKrefSetup because // it checks the flag, but it is more optimal to check the // flag before making the call because most of the time it will // be false. KrefCntrlFree( pDb); } goto Unlink_From_Trans; } #ifdef FLM_DBG_LOG flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, 0, 0, FERR_OK, "TAbrt"); #endif pFile->pRfl->clearLogHdrs(); // If the transaction had no update operations, restore it // to its pre-transaction state - make it appear that no // transaction ever happened. pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0]; pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0]; uiTransId = pDb->LogHdr.uiCurrTransID; // Free up all keys associated with this database. This is done even // if we didn't have any update operations because the KREF may // have been initialized by key generation operations performed // by cursors, etc. KrefCntrlFree( pDb); // Free any index counts we may have allocated. FSFreeIxCounts( pDb); if (pDb->bHadUpdOper) { // Dump any BLOB structures that should be aborted. FBListAfterAbort( pDb); // Dump any start and stop indexing stubs that should be aborted. flmIndexingAfterAbort( pDb); // Log the abort record to the rfl file, or throw away the logged // records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL // flag. If the RFL volume is bad, we will not attempt to keep this // transaction in the RFL. if (!pFile->pRfl->seeIfRflVolumeOk()) { bKeepAbortedTrans = FALSE; } else { bKeepAbortedTrans = (pucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL]) ? TRUE : FALSE; } } else { bKeepAbortedTrans = FALSE; } // Log an abort transaction record to the roll-forward log or // throw away the entire transaction, depending on the // bKeepAbortedTrans flag. // If the transaction is being "dumped" because of a failed commit, // don't log anything to the RFL. if( bOkToLogAbort) { flmAssert( pDb->LogHdr.uiCurrTransID == pFile->pRfl->getCurrTransID()); if (RC_BAD( rc = pFile->pRfl->logEndTransaction( RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans))) { goto Exit1; } } #ifdef FLM_DEBUG else { // If bOkToLogAbort is FALSE, this always means that either a // commit failed while trying to log an end transaction packet or a // commit packet was logged and the transaction commit subsequently // failed for some other reason. In either case, the RFL should be // in a good state, with its current transaction ID reset to 0. If // not, either bOkToLogAbort is being used incorrectly by the caller // or there is a bug in the RFL logic. flmAssert( pFile->pRfl->getCurrTransID() == 0); } #endif // If there were no operations in the transaction, restore // everything as if the transaction never happened. if (!pDb->bHadUpdOper) { f_mutexLock( gv_FlmSysData.hShareMutex); pFile->uiUpdateTransID = 0; f_mutexUnlock( gv_FlmSysData.hShareMutex); // Pretend we dumped cache - shouldn't be any to worry about at // this point. bDumpedCache = TRUE; goto Exit1; } // Dump ALL modified cache blocks associated with the DB. // NOTE: This needs to be done BEFORE the call to flmGetLogHdrInfo // below, because that call will change pDb->LogHdr.uiCurrTransID, // and that value is used by flmRcaAbortTrans. ScaFreeModifiedBlocks( pDb); flmRcaAbortTrans( pDb); bDumpedCache = TRUE; // Reset the LogHdr from the last committed log header in pFile. flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); if (RC_BAD( rc = flmPhysRollback( pDb, (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_ROLLBACK_EOF]), pFile->uiFirstLogBlkAddress, FALSE, 0))) { goto Exit1; } f_mutexLock( gv_FlmSysData.hShareMutex); // Put the new transaction ID into the log header even though // we are not committing. We want to keep the transaction IDs // incrementing even though we aborted. UD2FBA( (FLMUINT32)uiTransId, &pucLastCommittedLogHdr [LOG_CURR_TRANS_ID]); // Preserve where we are at in the roll-forward log. Even though // the transaction aborted, we may have kept it in the RFL instead of // throw it away. f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_FILE_NUM], &pucUncommittedLogHdr [LOG_RFL_FILE_NUM], 4); f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], 4); f_memcpy( &pucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], F_SERIAL_NUM_SIZE); f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], F_SERIAL_NUM_SIZE); // The following items tell us where we are at in the roll-back log. // During a transaction we may log blocks for the checkpoint or for // read transactions. So, even though we are aborting this transaction, // there may be other things in the roll-back log that we don't want // to lose. These items should not be reset until we do a checkpoint, // which is when we know it is safe to throw away the entire roll-back log. f_memcpy( &pucLastCommittedLogHdr [LOG_ROLLBACK_EOF], &pucUncommittedLogHdr [LOG_ROLLBACK_EOF], 4); f_memcpy( &pucLastCommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], &pucUncommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], 4); f_mutexUnlock( gv_FlmSysData.hShareMutex); pFile->pRfl->commitLogHdrs( pucLastCommittedLogHdr, pFile->ucCheckpointLogHdr); Exit1: // Dump cache, if not done above. if (!bDumpedCache) { ScaFreeModifiedBlocks( pDb); flmRcaAbortTrans( pDb); bDumpedCache = TRUE; } // Throw away IXD_FIXUPs if (pDb->pIxdFixups) { IXD_FIXUP * pIxdFixup; IXD_FIXUP * pDeleteIxdFixup; pIxdFixup = pDb->pIxdFixups; while (pIxdFixup) { pDeleteIxdFixup = pIxdFixup; pIxdFixup = pIxdFixup->pNext; f_free( &pDeleteIxdFixup); } pDb->pIxdFixups = NULL; } if (uiTransType != FLM_READ_TRANS && gv_FlmSysData.UpdateEvents.pEventCBList) { flmTransEventCallback( F_EVENT_ABORT_TRANS, (HFDB)pDb, rc, uiTransId); } Unlink_From_Trans: bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE; if (pDb->uiFlags & FDB_HAS_WRITE_LOCK) { RCODE tmpRc; if (RC_BAD( tmpRc = pFile->pRfl->completeTransWrites( pDb, FALSE, FALSE))) { if (RC_OK( rc)) { rc = tmpRc; } } } // Unlink the database from the transaction // structure as well as from the FLDICT structure. flmUnlinkDbFromTrans( pDb, FALSE); if (pDbStats) { FLMUINT64 ui64ElapMilli = 0; flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli); pDbStats->bHaveStats = TRUE; if (uiTransType == FLM_READ_TRANS) { pDbStats->ReadTransStats.AbortedTrans.ui64Count++; pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli += ui64ElapMilli; if (bInvisibleTrans) { pDbStats->ReadTransStats.InvisibleTrans.ui64Count++; pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli += ui64ElapMilli; } } else { pDbStats->UpdateTransStats.AbortedTrans.ui64Count++; pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli += ui64ElapMilli; } } if (pDb->pStats) { (void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats); } Exit: return( rc); }
/**************************************************************************** Desc: Prints the web page for an SCACHEMGR struct (The URL for this page requires no parameters since there is only one SCACHE_MGR per copy of FLAIM.) ****************************************************************************/ RCODE F_SCacheMgrPage::display( FLMUINT uiNumParams, const char ** ppszParams) { RCODE rc = FERR_OK; SCACHE_MGR LocalSCacheMgr; FLMBOOL bAutoRefresh; #define NUM_CACHE_REQ_STRINGS 4 char * pszSCacheRequestString[ NUM_CACHE_REQ_STRINGS]; char szOffsetTable[12][6]; char szAddressTable[2][20]; FLMBOOL bHighlight = FALSE; char * pszTemp = NULL; FLMUINT uiLoop; // Note: The SCacheBlock requests need the following params: // "BlockAddress", "File", "LowTransID" and "HighTransID" // ex: <A href="SCacheBlock?BlockAddress=100?File=5?LowTransID=30?HighTransID=100"> pMRUCache </A> if( RC_BAD( rc = f_alloc( 200, &pszTemp))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } // First thing that we need to do is grab a local copy of gv_FlmSysData.SCacheMgr, // and of the data for the three SCache blocks that it has pointers to... for (uiLoop = 0; uiLoop < NUM_CACHE_REQ_STRINGS; uiLoop++) { if( RC_BAD( rc = f_alloc( 150, &pszSCacheRequestString[ uiLoop]))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } } f_mutexLock( gv_FlmSysData.hShareMutex); f_memcpy (&LocalSCacheMgr, &gv_FlmSysData.SCacheMgr, sizeof (LocalSCacheMgr)); flmBuildSCacheBlockString( pszSCacheRequestString[0], LocalSCacheMgr.pMRUCache); flmBuildSCacheBlockString( pszSCacheRequestString[1], LocalSCacheMgr.pLRUCache); flmBuildSCacheBlockString( pszSCacheRequestString[2], LocalSCacheMgr.pFirstFree); flmBuildSCacheBlockString( pszSCacheRequestString[3], LocalSCacheMgr.pLastFree); f_mutexUnlock( gv_FlmSysData.hShareMutex); bAutoRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh"); // Now - are we being asked to display the usage stats? Or is this a regular page... if (DetectParameter( uiNumParams, ppszParams, "Usage")) { // There's a function to handle display the usage info (because both // RCacheMgr and SCacheMgr have usage stats). writeUsage( &LocalSCacheMgr.Usage, bAutoRefresh, "/SCacheMgr?Usage", "Usage Statistics for the SCache"); } else // This is a regular SCacheMgr page... { // Determine if we are being requested to refresh this page or not. stdHdr(); fnPrintf( m_pHRequest, HTML_DOCTYPE "<HTML>\n"); if (bAutoRefresh) { // Send back the page with a refresh command in the header fnPrintf( m_pHRequest, "<HEAD>" "<META http-equiv=\"refresh\" content=\"5; url=%s/SCacheMgr?Refresh\">" "<TITLE>gv_FlmSysData.SCacheMgr</TITLE>\n", m_pszURLString); printStyle(); popupFrame(); //Spits out a Javascript function that will open a new window.. fnPrintf( m_pHRequest, "\n</HEAD>\n<body>\n"); f_sprintf( (char *)pszTemp, "<A HREF=%s/SCacheMgr>Stop Auto-refresh</A>", m_pszURLString); } else // bAutoRefresh == FALSE { // Send back a page without the refresh command fnPrintf( m_pHRequest, "<HEAD>" "<TITLE>gv_FlmSysData.SCacheMgr</TITLE>\n"); printStyle(); popupFrame(); //Spits out a Javascript function that will open a new window.. fnPrintf( m_pHRequest, "\n</HEAD>\n<body>\n"); f_sprintf( (char *)pszTemp, "<A HREF=%s/SCacheMgr?Refresh>Start Auto-refresh (5 sec.)</A>", m_pszURLString); } // Write out the table headings printTableStart( "SCache Manager Structure", 4); printTableRowStart(); printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); fnPrintf( m_pHRequest, "<A HREF=%s/SCacheMgr>Refresh</A>, %s\n", m_pszURLString, pszTemp); printColumnHeadingClose(); printTableRowEnd(); // Write out the table headings. printTableRowStart(); printColumnHeading( "Byte Offset (hex)"); printColumnHeading( "Field Name"); printColumnHeading( "Field Type"); printColumnHeading( "Value"); printTableRowEnd(); //Now - we have three rows in the table that may or may not have hyperlinks in them. printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[0], "pMRUCache", &LocalSCacheMgr, &LocalSCacheMgr.pMRUCache); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[1], "pLRUCache", &LocalSCacheMgr, &LocalSCacheMgr.pLRUCache); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[2], "pFirstFree", &LocalSCacheMgr, &LocalSCacheMgr.pFirstFree); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[3], "pLastFree", &LocalSCacheMgr, &LocalSCacheMgr.pLastFree); //Format the strings that are displayed in the Offset column on of the table printOffset(&LocalSCacheMgr, &LocalSCacheMgr.ppHashTbl, szOffsetTable[0]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.Usage, szOffsetTable[1]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.bAutoCalcMaxDirty, szOffsetTable[2]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiMaxDirtyCache, szOffsetTable[3]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiLowDirtyCache, szOffsetTable[4]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiTotalUses, szOffsetTable[5]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiBlocksUsed, szOffsetTable[6]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiPendingReads, szOffsetTable[7]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiIoWaits, szOffsetTable[8]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiHashTblSize, szOffsetTable[9]); printOffset(&LocalSCacheMgr, &LocalSCacheMgr.uiHashTblBits, szOffsetTable[10]); #ifdef FLM_DEBUG printOffset(&LocalSCacheMgr, &LocalSCacheMgr.bDebug, szOffsetTable[11]); #endif printAddress( LocalSCacheMgr.ppHashTbl, szAddressTable[0]); printAddress( &LocalSCacheMgr.Usage, szAddressTable[1]); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td><A HREF=\"%s/SCacheHashTable?Start=0\">ppHashTbl</A></td>\n" "<td>SCACHE **</td>\n" "<td><A href=\"%s/SCacheHashTbl\">%s</A></td>\n", szOffsetTable[0], m_pszURLString, m_pszURLString, szAddressTable[0]); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td><A href=\"javascript:openPopup('%s/SCacheMgr?Usage')\">Usage</A></td>\n" "<td>FLM_CACHE_USAGE</td>\n" "<td><A href=\"javascript:openPopup('%s/SCacheMgr?Usage')\">%s</A></td>\n", szOffsetTable[1], m_pszURLString, m_pszURLString, szAddressTable[1]); printTableRowEnd(); // uiFreeCount printHTMLUint( (char *)"uiFreeCount", (char *)"FLMUINT", (void *)&LocalSCacheMgr, (void *)&LocalSCacheMgr.uiFreeCount, LocalSCacheMgr.uiFreeCount, (bHighlight = ~bHighlight)); // uiFreeBytes printHTMLUint( (char *)"uiFreeBytes", (char *)"FLMUINT", (void *)&LocalSCacheMgr, (void *)&LocalSCacheMgr.uiFreeBytes, LocalSCacheMgr.uiFreeBytes, (bHighlight = ~bHighlight)); // uiReplaceableCount printHTMLUint( (char *)"uiReplaceableCount", (char *)"FLMUINT", (void *)&LocalSCacheMgr, (void *)&LocalSCacheMgr.uiReplaceableCount, LocalSCacheMgr.uiReplaceableCount, (bHighlight = ~bHighlight)); // uiReplaceableBytes printHTMLUint( (char *)"uiReplaceableBytes", (char *)"FLMUINT", (void *)&LocalSCacheMgr, (void *)&LocalSCacheMgr.uiReplaceableBytes, LocalSCacheMgr.uiReplaceableBytes, (bHighlight = ~bHighlight)); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>bAutoCalcMaxDirty</td>\n" "<td>FLMBOOL</td>\n" TD_i, szOffsetTable[2], LocalSCacheMgr.bAutoCalcMaxDirty); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiMaxDirtyCache</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[3], LocalSCacheMgr.uiMaxDirtyCache); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiLowDirtyCache</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[4], LocalSCacheMgr.uiLowDirtyCache); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiTotalUses</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[5], LocalSCacheMgr.uiTotalUses); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiBlocksUsed</td> <td>FLMUINT</td>\n" TD_lu, szOffsetTable[6], LocalSCacheMgr.uiBlocksUsed); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiPendingReads</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[7], LocalSCacheMgr.uiPendingReads); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiIoWaits</td>\n <td>FLMUINT</td>\n" TD_lu, szOffsetTable[8], LocalSCacheMgr.uiIoWaits); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiHashTableSize</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[9], LocalSCacheMgr.uiHashTblSize); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiHashTableBits</td>\n" "<td>FLMUINT</td>\n" TD_lu, szOffsetTable[10], LocalSCacheMgr.uiHashTblBits); printTableRowEnd(); #ifdef FLM_DEBUG printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>bDebug</td>\n" "<td>FLMBOOL</td>\n" TD_i, szOffsetTable[11], LocalSCacheMgr.bDebug); printTableRowEnd(); #endif printTableEnd(); fnPrintf( m_pHRequest, "</BODY></HTML>\n"); fnEmit(); } Exit: if (pszTemp) { f_free( &pszTemp); } for (uiLoop = 0; uiLoop < NUM_CACHE_REQ_STRINGS; uiLoop++) { if( pszSCacheRequestString[uiLoop]) { f_free( &pszSCacheRequestString[uiLoop]); } } return( rc); }
/**************************************************************************** Desc: This routine is used to see if a file is already in use somewhere. This is only called for files which are opened directly by the application. Notes: This routine assumes that the global mutex is locked, but it may unlock and re-lock the mutex if needed. ****************************************************************************/ RCODE F_DbSystem::findDatabase( const char * pszDbPath, const char * pszDataDir, F_Database ** ppDatabase) { RCODE rc = NE_XFLM_OK; F_BUCKET * pBucket; FLMUINT uiBucket; FLMBOOL bMutexLocked = TRUE; F_Database * pDatabase; char szDbPathStr1 [F_PATH_MAX_SIZE]; char szDbPathStr2 [F_PATH_MAX_SIZE]; F_SEM hWaitSem = F_SEM_NULL; *ppDatabase = NULL; // Normalize the path to a string before looking for it. // NOTE: On non-UNIX, non-WIN platforms, this will basically convert // the string to upper case. if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( pszDbPath, szDbPathStr1))) { goto Exit; } Retry: *ppDatabase = NULL; if( !bMutexLocked) { f_mutexLock( gv_XFlmSysData.hShareMutex); bMutexLocked = TRUE; } pBucket = gv_XFlmSysData.pDatabaseHashTbl; uiBucket = f_strHashBucket( szDbPathStr1, pBucket, FILE_HASH_ENTRIES); pDatabase = (F_Database *)pBucket [uiBucket].pFirstInBucket; while (pDatabase) { // Compare the strings. On non-Unix platforms we must use // f_stricmp, because case does not matter for file names // on those platforms. #ifdef FLM_UNIX if( f_strcmp( szDbPathStr1, pDatabase->m_pszDbPath) == 0) #else if( f_stricmp( szDbPathStr1, pDatabase->m_pszDbPath) == 0) #endif { // Make sure data paths match. if (pszDataDir && *pszDataDir) { if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathToStorageString( pszDataDir, szDbPathStr2))) { goto Exit; } if (pDatabase->m_pszDataDir) { // f_stricmp must be used on non-unix platforms because file // names are case insensitive on those platforms. #ifdef FLM_UNIX if (f_strcmp( pDatabase->m_pszDataDir, szDbPathStr2) != 0) #else if (f_stricmp( pDatabase->m_pszDataDir, szDbPathStr2) != 0) #endif { rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH); goto Exit; } } else { rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH); goto Exit; } } else if (pDatabase->m_pszDataDir) { rc = RC_SET( NE_XFLM_DATA_PATH_MISMATCH); goto Exit; } *ppDatabase = pDatabase; break; } pDatabase = pDatabase->m_pNext; } if (*ppDatabase && pDatabase->m_uiFlags & DBF_BEING_CLOSED) { if( RC_BAD( rc = f_semCreate( &hWaitSem))) { goto Exit; } // Put ourselves into the notify list and then re-try // the lookup when we wake up if (RC_BAD( rc = f_notifyWait( gv_XFlmSysData.hShareMutex, hWaitSem, NULL, &pDatabase->m_pCloseNotifies))) { goto Exit; } f_semDestroy( &hWaitSem); // The mutex will be locked at this point. Re-try the lookup. // IMPORTANT NOTE: pDatabase will have been destroyed by this // time. DO NOT use it for anything! goto Retry; } Exit: if( hWaitSem != F_SEM_NULL) { f_semDestroy( &hWaitSem); } // Make sure the global mutex is re-locked before exiting if( !bMutexLocked) { f_mutexLock( gv_XFlmSysData.hShareMutex); } return( rc); }
/**************************************************************************** Desc: This routine will open a database, returning a pointer to an IF_Db object that can be used to access it. ****************************************************************************/ RCODE F_DbSystem::openDatabase( F_Database * pDatabase, const char * pszDbPath, const char * pszDataDir, const char * pszRflDir, const char * pszPassword, FLMUINT uiOpenFlags, FLMBOOL bInternalOpen, IF_RestoreClient * pRestoreObj, IF_RestoreStatus * pRestoreStatus, IF_FileHdl * pLockFileHdl, IF_Db ** ppDb) { RCODE rc = NE_XFLM_OK; FLMBOOL bNewDatabase = FALSE; FLMBOOL bMutexLocked = FALSE; F_Db * pDb = NULL; FLMBOOL bNeedToOpen = FALSE; // Allocate and initialize an F_Db object. if (RC_BAD( rc = allocDb( &pDb, bInternalOpen))) { goto Exit; } f_mutexLock( gv_XFlmSysData.hShareMutex); bMutexLocked = TRUE; // Look up the file using findDatabase to see if we already // have the file open. if (!pDatabase) { bNeedToOpen = TRUE; // May unlock and re-lock the global mutex. if (RC_BAD( rc = findDatabase( pszDbPath, pszDataDir, &pDatabase))) { goto Exit; } } if (pDatabase) { if( RC_BAD( rc = pDatabase->checkState( __FILE__, __LINE__))) { goto Exit; } } if (!pDatabase) { if (RC_BAD( rc = allocDatabase( pszDbPath, pszDataDir, FALSE, &pDatabase))) { goto Exit; } flmAssert( !pLockFileHdl); bNewDatabase = TRUE; } else if( pLockFileHdl) { flmAssert( pDatabase); flmAssert( !pDatabase->m_uiOpenIFDbCount); flmAssert( pDatabase->m_uiFlags & DBF_BEING_OPENED); pDatabase->m_pLockFileHdl = pLockFileHdl; // Set to NULL to prevent lock file from being released below pLockFileHdl = NULL; bNewDatabase = TRUE; bNeedToOpen = TRUE; } else { FLMBOOL bWaited = FALSE; flmAssert( !pLockFileHdl); if (RC_BAD( rc = pDatabase->verifyOkToUse( &bWaited))) { goto Exit; } if (bWaited) { bNewDatabase = FALSE; bNeedToOpen = FALSE; } } // Link the F_Db object to the F_Database object. rc = pDb->linkToDatabase( pDatabase); f_mutexUnlock( gv_XFlmSysData.hShareMutex); bMutexLocked = FALSE; if (RC_BAD(rc)) { goto Exit; } (void)flmStatGetDb( &pDb->m_Stats, pDatabase, 0, &pDb->m_pDbStats, NULL, NULL); if (bNeedToOpen) { if (RC_BAD( rc = pDatabase->physOpen( pDb, pszDbPath, pszRflDir, pszPassword, uiOpenFlags, bNewDatabase, pRestoreObj, pRestoreStatus))) { goto Exit; } } // Start a checkpoint thread if( bNewDatabase && !(uiOpenFlags & XFLM_DONT_REDO_LOG)) { flmAssert( !pDatabase->m_pCPThrd); flmAssert( !pDatabase->m_pMaintThrd); if( RC_BAD( rc = pDatabase->startCPThread())) { goto Exit; } if( !(uiOpenFlags & XFLM_DONT_RESUME_THREADS)) { if( RC_BAD( rc = pDb->startBackgroundIndexing())) { goto Exit; } if( RC_BAD( rc = pDatabase->startMaintThread())) { goto Exit; } } } Exit: if (bMutexLocked) { f_mutexUnlock( gv_XFlmSysData.hShareMutex); } if (pLockFileHdl) { pLockFileHdl->Release(); } if (pDb) { // completeOpenOrCreate will delete pDb if RC_BAD( rc) pDb->completeOpenOrCreate( rc, bNewDatabase); if (RC_BAD( rc)) { pDb = NULL; } } *ppDb = (IF_Db *)pDb; return( rc); }
/**************************************************************************** Desc: This is the function that the HTTP server calls when it wants to display one of our pages ****************************************************************************/ int flmHttpCallback( HRequest * pHRequest, void * //pvUserData ) { RCODE rc = FERR_OK; F_WebPage * pPage = NULL; char * pszPath = NULL; char * pszQuery = NULL; char * pszTemp = NULL; const char * pszConstTemp = NULL; #define MAX_PARAMS 10 const char * pszParams[ MAX_PARAMS]; FLMUINT uiNumParams; // If we get a NULL for the pHRequest object, then we are shutting down... if (pHRequest == NULL) { // Remove the globals that enable the secure pages... gv_FlmSysData.HttpConfigParms.fnSetGblValue( FLM_SECURE_PASSWORD, "", 0); gv_FlmSysData.HttpConfigParms.fnSetGblValue( FLM_SECURE_EXPIRATION, "", 0); // Delete the web page factory object if (gv_pWPFact) { gv_pWPFact->Release( NULL); } gv_pWPFact = NULL; goto Exit; } // Increment the use count (helps ensure that the function pointers // that display() references don't go away while display() still needs // them. f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex); gv_FlmSysData.HttpConfigParms.uiUseCount++; f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex); // Must not access any HRequest function pointers prior to incrementing the // use count. if( !gv_FlmSysData.HttpConfigParms.fnReqPath) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } // If the web page factory does not exist yet, then we need to create it. if (!gv_pWPFact) { f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex); // In the time it took us to get the lock, some other thread might // have come along and created the factory already... if (!gv_pWPFact) { if ((gv_pWPFact = f_new F_WebPageFactory) == NULL) { rc = RC_SET( FERR_MEM); f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex); goto Exit; } } f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex); } pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqPath( pHRequest); flmAssert( pszConstTemp); if( RC_BAD( rc = f_alloc( f_strlen( pszConstTemp) + 1, &pszPath))) { goto Exit; } f_strcpy( pszPath, pszConstTemp); pszConstTemp = gv_FlmSysData.HttpConfigParms.fnReqQuery( pHRequest); if( pszConstTemp) { if( RC_BAD( rc = f_alloc( f_strlen( pszConstTemp) + 1, &pszQuery))) { goto Exit; } f_strcpy( pszQuery, pszConstTemp); pszConstTemp = pszQuery; } else // This URL had no query string... { // If pszQuery is NULL, it causes problems further down, so we'll // make it a pointer to a null string... if( RC_BAD( rc = f_alloc( 1, &pszQuery))) { goto Exit; } pszQuery[0] = '\0'; } // Strip off pszURLString (and the next '/', if there is one) from the request and store // what's left as pszParams[0]. // (ie: /coredb/FlmSysData --> FlmSysData) // Note: The reason we're checking for the URL string first is because if // we're using our own http stack, then this callback is called for every // http request and we don't want to crash if we've got a short URI. // When we're running under DS, we're guarenteed that the URLString will // be part of the URI. if( f_strlen( pszPath) >= gv_FlmSysData.HttpConfigParms.uiURLStringLen) { pszConstTemp = pszPath + gv_FlmSysData.HttpConfigParms.uiURLStringLen; if( *pszConstTemp == '/') { pszConstTemp++; } } else { pszConstTemp = pszPath; } pszParams[0] = pszConstTemp; uiNumParams = 1; // Parse parameters in the query string // Note that it's technically incorrect to have more than one ? in a // URL, but we didn't know that when we first started creating some of // these pages and as a result, some queries are in the form of: // ?name1=value1?name2=value2?name3=value3... (which is improper) and // some have the form: // ?name1=value1&name2=value2&name3=value3... (which is correct). pszTemp = pszQuery; while( *pszTemp != 0) { flmAssert( uiNumParams < MAX_PARAMS); pszParams[ uiNumParams] = pszTemp; uiNumParams++; pszTemp = tokenizer( pszTemp, '?', '&'); if (*pszTemp) { *pszTemp = '\0'; pszTemp++; } } // Tell the factory to create the page if (RC_BAD( rc = gv_pWPFact->create( pszParams[0], &pPage, pHRequest))) { goto Exit; } pPage->setMembers( pHRequest); // display the page if( RC_BAD( rc = pPage->display (uiNumParams, &pszParams[0]))) { goto Exit; } Exit: // Decrement the use count if( pHRequest) { f_mutexLock( gv_FlmSysData.HttpConfigParms.hMutex); if( gv_FlmSysData.HttpConfigParms.uiUseCount > 0) { gv_FlmSysData.HttpConfigParms.uiUseCount--; } else { flmAssert( 0); } f_mutexUnlock( gv_FlmSysData.HttpConfigParms.hMutex); } if (pPage) { gv_pWPFact->Release( &pPage); } if (pszPath) { f_free( &pszPath); } if (pszQuery) { f_free( &pszQuery); } return (int)rc; }
/**************************************************************************** Desc: Prints the web page for an SCACHE struct ****************************************************************************/ RCODE F_SCacheBlockPage::display( FLMUINT uiNumParams, const char ** ppszParams) { RCODE rc = FERR_OK; FLMUINT uiBlkAddress = 0; FLMUINT uiLowTransID = 0; FLMUINT uiHighTransID = 0; FFILE * pFile; FLMBOOL bHighlight = FALSE; char * pszTemp = NULL; char * pszTemp1 = NULL; FLMUINT uiLoop = 0; char szOffsetTable[10][6]; char szAddressTable[4][20]; SCACHE LocalSCacheBlock; FLMUINT uiPFileBucket = 0; char * pszSCacheRequestString[8] = {0, 0, 0, 0, 0, 0, 0, 0}; char * pszSCacheDataRequest = NULL; char * pszSCacheAutoRequest = NULL; char * pszSCacheUseListRequest = NULL; char * pszSCacheNotifyListRequest = NULL; char * pszFFileRequest = NULL; char * pszFlagNames = NULL; if( RC_BAD( rc = f_alloc( 200, &pszTemp))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } if( RC_BAD( rc = f_alloc( 200, &pszTemp1))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } // Allocate memory for all those string pointers we declared above... for (uiLoop = 0; uiLoop < 8; uiLoop++) { if( RC_BAD( rc = f_alloc( 150, &pszSCacheRequestString[ uiLoop]))) { goto Exit; } } if( RC_BAD( rc = f_alloc( 150, &pszSCacheDataRequest))) { goto Exit; } if( RC_BAD( rc = f_alloc( 150, &pszSCacheAutoRequest))) { goto Exit; } if( RC_BAD( rc = f_alloc( 150, &pszSCacheUseListRequest))) { goto Exit; } if( RC_BAD( rc = f_alloc( 150, &pszSCacheNotifyListRequest))) { goto Exit; } if( RC_BAD( rc = f_alloc( 100, &pszFFileRequest))) { goto Exit; } if( RC_BAD( rc = f_alloc( 100, &pszFlagNames))) { goto Exit; } f_mutexLock( gv_FlmSysData.hShareMutex); rc = locateSCacheBlock( uiNumParams, ppszParams, &LocalSCacheBlock, &uiBlkAddress, &uiLowTransID, &uiHighTransID, &pFile); if (RC_OK(rc) && LocalSCacheBlock.pFile) { uiPFileBucket = LocalSCacheBlock.pFile->uiBucket; } if (RC_OK( rc)) { // Build the proper strings to request various other SCache blocks flmBuildSCacheBlockString( pszSCacheRequestString[0], LocalSCacheBlock.pPrevInFile); flmBuildSCacheBlockString( pszSCacheRequestString[1], LocalSCacheBlock.pNextInFile); flmBuildSCacheBlockString( pszSCacheRequestString[2], LocalSCacheBlock.pPrevInGlobalList); flmBuildSCacheBlockString( pszSCacheRequestString[3], LocalSCacheBlock.pNextInGlobalList); flmBuildSCacheBlockString( pszSCacheRequestString[4], LocalSCacheBlock.pPrevInHashBucket); flmBuildSCacheBlockString( pszSCacheRequestString[5], LocalSCacheBlock.pNextInHashBucket); flmBuildSCacheBlockString( pszSCacheRequestString[6], LocalSCacheBlock.pPrevInVersionList); flmBuildSCacheBlockString( pszSCacheRequestString[7], LocalSCacheBlock.pNextInVersionList); // Build the proper string to request the current Page flmBuildSCacheBlockString( pszSCacheAutoRequest, &LocalSCacheBlock); } f_mutexUnlock( gv_FlmSysData.hShareMutex); if (RC_BAD( rc)) { if (rc == FERR_NOT_FOUND) { // The block wasn't there, print an error message and exit notFoundErr(); rc = FERR_OK; } else if (rc == FERR_MEM) { // Parameters were too long to store in the space provided. // Probably means that the URL was malformed... malformedUrlErr(); rc = FERR_OK; } goto Exit; } //Build the proper string to request this block's data... printAddress( pFile, szAddressTable[0]); f_sprintf( (char *)pszSCacheDataRequest, "%s/SCacheData?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu", m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0], uiLowTransID, uiHighTransID); #ifdef FLM_DEBUG //Build the proper string to request this block's use list if( LocalSCacheBlock.pUseList) { f_sprintf( (char *)pszSCacheUseListRequest, "%s/SCacheUseList?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu", m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0], uiLowTransID, uiHighTransID); } else { pszSCacheUseListRequest[0] = '\0'; } #endif //Build the proper string to request the notify list data... if (LocalSCacheBlock.pNotifyList) { f_sprintf( (char *)pszSCacheNotifyListRequest, "%s/SCacheNotifyList?BlockAddress=%lu&File=%s&LowTransID=%lu&HighTransID=%lu", m_pszURLString, LocalSCacheBlock.uiBlkAddress, szAddressTable[0], uiLowTransID, uiHighTransID); } else { pszSCacheNotifyListRequest[0] = '\0'; } //Build the proper string to request the FFile printAddress( LocalSCacheBlock.pFile, szAddressTable[0]); f_sprintf( (char *)pszFFileRequest, "%s/FFile?From=SCacheBlock&Bucket=%lu&Address=%s", m_pszURLString, uiPFileBucket, szAddressTable[0]); // Build a string with the names of all the flags that have been set... pszFlagNames[0]='\0'; if (LocalSCacheBlock.ui16Flags & CA_DIRTY) { f_strcat( pszFlagNames, "<BR> CA_DIRTY"); } if (LocalSCacheBlock.ui16Flags & CA_READ_PENDING) { f_strcat( pszFlagNames, "<BR> CA_READ_PENDING"); } if (LocalSCacheBlock.ui16Flags & CA_WRITE_TO_LOG) { f_strcat( pszFlagNames, "<BR> CA_WRITE_TO_LOG"); } if (LocalSCacheBlock.ui16Flags & CA_LOG_FOR_CP) { f_strcat( pszFlagNames, "<BR> CA_LOG_FOR_CP"); } if (LocalSCacheBlock.ui16Flags & CA_WAS_DIRTY) { f_strcat( pszFlagNames, "<BR> CA_WAS_DIRTY"); } if (LocalSCacheBlock.ui16Flags & CA_WRITE_PENDING) { f_strcat( pszFlagNames, "<BR> CA_WRITE_PENDING"); } if (LocalSCacheBlock.ui16Flags & CA_IN_WRITE_PENDING_LIST) { f_strcat( pszFlagNames, "<BR> CA_IN_WRITE_PENDING_LIST"); } // OK - Start outputting HTML... stdHdr(); fnPrintf( m_pHRequest, HTML_DOCTYPE "<html>\n"); // Determine if we are being requested to refresh this page or not. if (DetectParameter( uiNumParams, ppszParams, "Refresh")) { // Send back the page with a refresh command in the header fnPrintf( m_pHRequest, "<HEAD>\n" "<META http-equiv=\"refresh\" content=\"5; url=\"%s\">" "<TITLE>SCache Block</TITLE>\n", pszSCacheAutoRequest); printStyle(); popupFrame(); //Spits out a Javascript function that will open a new window.. fnPrintf( m_pHRequest, "</HEAD>\n<body>\n"); f_sprintf( (char*)pszTemp, "<A HREF=\"%s\">Stop Auto-refresh</A>", pszSCacheAutoRequest); } else { // Send back a page without the refresh command fnPrintf( m_pHRequest, "<HEAD>\n"); printStyle(); popupFrame(); //Spits out a Javascript function that will open a new window.. fnPrintf( m_pHRequest, "</HEAD>\n<body>\n"); f_sprintf( (char *)pszTemp, "<A HREF=\"%s?Refresh\">Start Auto-refresh (5 sec.)</A>", pszSCacheAutoRequest); } // Write out the table headings printTableStart( "SCache Block Structure", 4, 100); printTableRowStart(); printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); fnPrintf( m_pHRequest, "<A HREF=\"%s\">Refresh</A>, %s\n", pszSCacheAutoRequest, pszTemp); printColumnHeadingClose(); printTableRowEnd(); // Write out the table headings. printTableRowStart(); printColumnHeading( "Byte Offset (hex)"); printColumnHeading( "Field Name"); printColumnHeading( "Field Type"); printColumnHeading( "Value"); printTableRowEnd(); // Print the two rows for pPrevInFile and pNextInFile printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[0], "pPrevInFile", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInFile); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[1], "pNextInFile", &LocalSCacheBlock, &LocalSCacheBlock.pNextInFile); // Format the strings that are displayed in the Offset and Address // columns of the table printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pucBlk, szOffsetTable[0]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pFile, szOffsetTable[1]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiBlkAddress, szOffsetTable[2]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pNotifyList, szOffsetTable[3]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiHighTransID, szOffsetTable[4]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiUseCount, szOffsetTable[5]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.ui16Flags, szOffsetTable[6]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.ui16BlkSize, szOffsetTable[7]); #ifdef FLM_DEBUG printOffset( &LocalSCacheBlock, &LocalSCacheBlock.uiChecksum, szOffsetTable[8]); printOffset( &LocalSCacheBlock, &LocalSCacheBlock.pUseList, szOffsetTable[9]); #endif printAddress( LocalSCacheBlock.pucBlk, szAddressTable[0]); printAddress( LocalSCacheBlock.pFile, szAddressTable[1]); printAddress( LocalSCacheBlock.pNotifyList, szAddressTable[2]); #ifdef FLM_DEBUG printAddress( LocalSCacheBlock.pUseList, szAddressTable[3]); #endif printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td><A HREF=\"javascript:openPopup('%s')\">pucBlk</A></td>\n" "<td>FLMBYTE *</td>\n<td><A HREF=\"javascript:openPopup('%s')\">%s</A></td>\n", szOffsetTable[0], pszSCacheDataRequest, pszSCacheDataRequest, szAddressTable[0] ); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td><A href=%s>pFile</A></td>\n" "<td>FFILE *</td>\n<td><A HREF=%s>%s</a></td>\n", szOffsetTable[1], pszFFileRequest, pszFFileRequest, szAddressTable[1]); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiBlkAddress</td>\n<td>FLMUINT</td>\n" "<td>0x%lX</td>\n", szOffsetTable[2], LocalSCacheBlock.uiBlkAddress); printTableRowEnd(); //Print the rows for the remaining SCache * fields printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[2], "pPrevInGlobalList", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInGlobalList); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[3], "pNextInGlobalList", &LocalSCacheBlock, &LocalSCacheBlock.pNextInGlobalList); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[4], "pPrevInHashBucket", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInHashBucket); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[5], "pNextInHashBucket", &LocalSCacheBlock, &LocalSCacheBlock.pNextInHashBucket); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[6], "pPrevInVersionList", &LocalSCacheBlock, &LocalSCacheBlock.pPrevInVersionList); printTableRowStart( bHighlight = ~bHighlight); flmPrintCacheLine(m_pHRequest, pszSCacheRequestString[7], "pNextInVersionList", &LocalSCacheBlock, &LocalSCacheBlock.pNextInVersionList); //Notify list line printTableRowStart( bHighlight = ~bHighlight); if (LocalSCacheBlock.pNotifyList) { fnPrintf( m_pHRequest, TD_s " <td> <A HREF=\"javascript:openPopup('%s')\"> pNotifyList </A> </td> <td>FNOTIFY *</td> " "<td> <A HREF=\"javascript:openPopup('%s')\"> %s </A> </td>", szOffsetTable[3], pszSCacheNotifyListRequest, pszSCacheNotifyListRequest, szAddressTable[2]); } else { fnPrintf( m_pHRequest, TD_s " <td> pNotifyList </td> <td>FNOTIFY *</td> " "<td> 0x0 </td>", szOffsetTable[3]); } printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiHighTransID</td>\n" "<td>FLMUINT</td>\n" TD_8x, szOffsetTable[4], LocalSCacheBlock.uiHighTransID); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiUseCount</td>\n<td>FLMUINT</td>\n" TD_lu, szOffsetTable[5], LocalSCacheBlock.uiUseCount); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>ui16Flags</td>\n<td>FLMUINT16</td>\n" "<td>0x%04X %s</td>\n", szOffsetTable[6], LocalSCacheBlock.ui16Flags, pszFlagNames); printTableRowEnd(); printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>ui16BlkSize</td>\n<td>FLMUINT16</td>\n" TD_i, szOffsetTable[7], LocalSCacheBlock.ui16BlkSize); printTableRowEnd(); #ifdef FLM_DEBUG printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "<td>uiChecksum</td>\n" "<td>FLMUINT</td>\n" TD_8x, szOffsetTable[8], LocalSCacheBlock.uiChecksum); printTableRowEnd(); #endif #ifdef FLM_DEBUG //Last line - the use list... printTableRowStart( bHighlight = ~bHighlight); if (LocalSCacheBlock.pUseList) { fnPrintf( m_pHRequest, TD_s " <td> <A href=\"javascript:openPopup('%s')> pUseList </A> </td> <td> SCACHE_USE_p </td> <td> <A href=\"javascript:openPopup('%s')> %s </A></td>", szOffsetTable[9], pszSCacheUseListRequest, pszSCacheUseListRequest, szAddressTable[3]); } else { fnPrintf( m_pHRequest, TD_s " <td> pUseList </td> <td> SCACHE_USE_p </td> <td> 0x0 </td>", szOffsetTable[9]); } printTableRowEnd(); #endif fnPrintf( m_pHRequest, TABLE_END "</BODY></HTML>\n"); fnEmit(); Exit: // Even though uiLoop2 is not in the same scope as uiLoop, VC6 still // complains if this is called uiLoop.... for (FLMUINT uiLoop2 = 0; uiLoop2 < 8; uiLoop2++) { if (pszSCacheRequestString[uiLoop2]) { f_free( &pszSCacheRequestString[uiLoop2]); } } if (pszSCacheDataRequest) { f_free( &pszSCacheDataRequest); } if (pszSCacheAutoRequest) { f_free( &pszSCacheAutoRequest); } if (pszSCacheUseListRequest) { f_free( &pszSCacheUseListRequest); } if (pszSCacheNotifyListRequest) { f_free( &pszSCacheNotifyListRequest); } if( pszFFileRequest) { f_free( &pszFFileRequest); } if( pszFlagNames) { f_free( &pszFlagNames); } if (pszTemp) { f_free( &pszTemp); } if (pszTemp1) { f_free( &pszTemp1); } return( rc); }
inline void lockMutex( void) { f_mutexLock( m_hMutex); }
/**************************************************************************** Desc: Prints the web page for the SCacheHashTable ****************************************************************************/ RCODE F_SCacheHashTablePage::display( FLMUINT uiNumParams, const char ** ppszParams) { RCODE rc = FERR_OK; FLMBOOL bRefresh; FLMBOOL bHighlight = TRUE; FLMUINT uiLoop; FLMUINT uiHashTableSize; FLMUINT uiUsedEntries = 0; char szStart[10]; char szRefresh[] = "&Refresh"; FLMUINT uiStart; FLMUINT uiNewStart; char * pszTemp; #define NUM_ENTRIES 20 char * pszHTLinks[NUM_ENTRIES]; F_UNREFERENCED_PARM( uiNumParams); F_UNREFERENCED_PARM( ppszParams); // Check for the refresh parameter bRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh"); if (!bRefresh) { szRefresh[0]='\0'; // Effectively turns szRefresh into a null string } // Get the starting entry number... if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Start", sizeof( szStart), szStart))) { flmAssert( 0); goto Exit; } uiStart = f_atoud( szStart); // Allocate space for the hyperlink text for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++) { if( RC_BAD( rc = f_alloc( 250, &pszHTLinks[ uiLoop]))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } pszHTLinks[uiLoop][0] = '\0'; } if( RC_BAD( rc = f_alloc( 250, &pszTemp))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } // Lock the database f_mutexLock( gv_FlmSysData.hShareMutex); // Get the number of entries in the hash table uiHashTableSize = gv_FlmSysData.SCacheMgr.uiHashTblSize; // May need to modify starting number if it's out of range... if ((uiStart + NUM_ENTRIES) >= uiHashTableSize) { uiStart = uiHashTableSize - NUM_ENTRIES; } // Loop through the entire table counting the number of entries in use // If the entry is one of the one's we're going to display, store the // appropriate text in pszHTLinks for (uiLoop = 0; uiLoop < uiHashTableSize; uiLoop++) { if (gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop]) { uiUsedEntries++; } if ( (uiLoop >= uiStart) && (uiLoop < (uiStart + NUM_ENTRIES)) ) { // This is one of the entries that we will display if (gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop]) { flmBuildSCacheBlockString( pszHTLinks[uiLoop - uiStart], gv_FlmSysData.SCacheMgr.ppHashTbl[uiLoop]); } } } // Unlock the database f_mutexUnlock( gv_FlmSysData.hShareMutex); // Begin rendering the page... stdHdr(); printStyle(); fnPrintf( m_pHRequest, HTML_DOCTYPE "<html>\n"); // Determine if we are being requested to refresh this page or not. if (bRefresh) { fnPrintf( m_pHRequest, "<HEAD>" "<META http-equiv=\"refresh\" content=\"5; url=%s/SCacheHashTable?Start=%lu%s\">" "<TITLE>Database iMonitor - SCache Hash Table</TITLE>\n", m_pszURLString, uiStart, szRefresh); } else { fnPrintf( m_pHRequest, "<HEAD>\n"); } // If we are not to refresh this page, then don't include the // refresh meta command if (!bRefresh) { f_sprintf( (char *)pszTemp, "<A HREF=%s/SCacheHashTable?Start=%lu&Refresh>Start Auto-refresh (5 sec.)</A>", m_pszURLString, uiStart); } else { f_sprintf( (char *)pszTemp, "<A HREF=%s/SCacheHashTable?Start=%lu>Stop Auto-refresh</A>", m_pszURLString, uiStart); } // Print out a formal header and the refresh option. printTableStart("SCache Hash Table", 4); printTableRowStart(); printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Refresh</A>, %s\n", m_pszURLString, uiStart, szRefresh, pszTemp); printColumnHeadingClose(); printTableRowEnd(); printTableRowStart( (bHighlight = !bHighlight)); fnPrintf( m_pHRequest, "<TD>Table Size: %lu </TD>\n", uiHashTableSize); printTableRowEnd(); printTableRowStart( (bHighlight = !bHighlight)); fnPrintf( m_pHRequest, "<TD>Entries Used: %lu (%lu%%) </TD>\n", uiUsedEntries, ((uiUsedEntries * 100) / uiHashTableSize) ); printTableRowEnd(); // The rest of the table is going to be a single row with two columns: // one for the list of hash buckets and the other for everything else printTableRowStart( FALSE); fnPrintf( m_pHRequest, " <TD>\n"); // Print out the hash buckets for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++) { if (pszHTLinks[uiLoop][0] != '\0') { fnPrintf( m_pHRequest, "<A HREF=%s%s>%lu</A> <br>\n", pszHTLinks[uiLoop], szRefresh, uiStart+uiLoop); } else { fnPrintf( m_pHRequest, "%lu<br>\n", uiStart+uiLoop); } } fnPrintf( m_pHRequest, "</ul>\n</TD>\n<TD>\n"); // Print out the other stuff... uiNewStart = (uiStart > 100)?(uiStart - 100):0; fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Previous 100</A> <BR>\n", m_pszURLString, uiNewStart, szRefresh); uiNewStart = (uiStart > 10)?(uiStart - 10):0; fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Previous 10</A> <BR>\n", m_pszURLString, uiNewStart, szRefresh); fnPrintf( m_pHRequest, "<BR>\n"); uiNewStart = (uiStart + 10); if (uiNewStart >= (uiHashTableSize - NUM_ENTRIES)) { uiNewStart = (uiHashTableSize - NUM_ENTRIES); } fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Next 10</A> <BR>\n", m_pszURLString, uiNewStart, szRefresh); uiNewStart = (uiStart + 100); if (uiNewStart >= (uiHashTableSize - NUM_ENTRIES)) { uiNewStart = (uiHashTableSize - NUM_ENTRIES); } fnPrintf( m_pHRequest, "<A HREF=%s/SCacheHashTable?Start=%lu%s>Next 100</A> <BR>\n" "<form type=\"submit\" method=\"get\" action=\"/coredb/SCacheHashTable\">\n" "<BR> Jump to specific bucket:<BR> \n" "<INPUT type=\"text\" size=\"10\" maxlength=\"10\" name=\"Start\"></INPUT> <BR>\n", m_pszURLString, uiNewStart, szRefresh); printButton( "Jump", BT_Submit); // We use a hidden field to pass the refresh parameter back the the server if (bRefresh) { fnPrintf( m_pHRequest, "<INPUT type=\"hidden\" name=\"Refresh\"></INPUT>\n"); } fnPrintf( m_pHRequest, "</form>\n</TD>\n"); printTableRowEnd(); printTableEnd(); printDocEnd(); fnEmit(); Exit: // Free the space for the hyperlink text for (uiLoop = 0; uiLoop < NUM_ENTRIES; uiLoop++) { f_free( &pszHTLinks[uiLoop]); } f_free( &pszTemp); return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogFlush( void) { f_mutexLock( g_hDbgLogMutex); _flmDbgLogFlush(); f_mutexUnlock( g_hDbgLogMutex); }
/**************************************************************************** Desc: This destructor frees all of the structures associated with an F_Database object. Whoever called this routine has already determined that it is safe to do so. Notes: The global mutex is assumed to be locked when entering the routine. It may be unlocked and re-locked before the routine exits, however. ****************************************************************************/ F_Database::~F_Database() { F_NOTIFY_LIST_ITEM * pCloseNotifies; F_Dict * pDict; F_Dict * pTmpDict; // At this point, the use count better be zero flmAssert( !m_uiOpenIFDbCount); // Shut down all background threads before shutting down the CP thread. shutdownDatabaseThreads(); if (m_pRfl) { m_pRfl->closeFile(); } // Shouldn't have any pending input at this point flmAssert( !m_pPendingInput); // At this point, the use count better be zero flmAssert( !m_uiOpenIFDbCount); // Unlock the mutex f_mutexUnlock( gv_XFlmSysData.hShareMutex); // Shut down the checkpoint thread if( m_pCPThrd) { m_pCPThrd->stopThread(); m_pCPThrd->Release(); m_pCPThrd = NULL; } // Unlink all of the F_Dict objects that are connected to the // database. lockMutex(); while (m_pDictList) { m_pDictList->unlinkFromDatabase(); } unlockMutex(); // Take the file out of its name hash bucket, if any. if (m_uiBucket != 0xFFFF) { f_mutexLock( gv_XFlmSysData.hShareMutex); if (m_pPrev) { m_pPrev->m_pNext = m_pNext; } else { gv_XFlmSysData.pDatabaseHashTbl[ m_uiBucket].pFirstInBucket = m_pNext; } if (m_pNext) { m_pNext->m_pPrev = m_pPrev; } m_uiBucket = 0xFFFF; // After this point, we should not need to keep the global mutex locked // because the F_Database is no longer visible to any thread to find in // the hash table. f_mutexUnlock( gv_XFlmSysData.hShareMutex); } // Shouldn't have any queries at this point. But we will be nice in case // we do and will unlink the queries from the list flmAssert( !m_pFirstQuery); while (m_pFirstQuery) { F_Query * pQuery = m_pFirstQuery; m_pFirstQuery = m_pFirstQuery->m_pNext; pQuery->m_pPrev = NULL; pQuery->m_pNext = NULL; pQuery->m_pDatabase = NULL; } // Free the RFL data, if any. if (m_pRfl) { m_pRfl->Release(); m_pRfl = NULL; } flmAssert( m_pOpenNotifies == NULL); m_pOpenNotifies = NULL; // Save pCloseNotifies -- we will notify any waiters once the // F_Database has been freed. pCloseNotifies = m_pCloseNotifies; // Free any dictionary usage structures associated with the database. pDict = m_pDictList; while (pDict) { pTmpDict = pDict; pDict = pDict->getNext(); pTmpDict->Release(); } m_pDictList = NULL; // Free any shared cache associated with the database. // IMPORTANT NOTE: // Cannot have the global mutex locked when these are called because // these routines lock the block cache mutex and the node cache mutex. // If both the global mutex and the block or node cache mutexes are to be // locked, the rule is that the block or node cache mutex must be locked // before locking the global mutex. This is because neededByReadTrans // will end up doing it in this order - when neededByReadTrans is called // either the block or node cache mutex is already locked, and it will // additionally lock the global mutex. Since that order is already // required, we cannot have anyone else attempting to lock the mutexes // in a different order. freeBlockCache(); freeNodeCache(); // Release the lock objects. if (m_pWriteLockObj) { m_pWriteLockObj->Release(); m_pWriteLockObj = NULL; } if (m_pDatabaseLockObj) { m_pDatabaseLockObj->Release(); m_pDatabaseLockObj = NULL; } // Close and delete the lock file. if (m_pLockFileHdl) { (void)m_pLockFileHdl->closeFile(); m_pLockFileHdl->Release(); m_pLockFileHdl = NULL; } // Free the write buffer managers. if (m_pBufferMgr) { m_pBufferMgr->Release(); m_pBufferMgr = NULL; } // Free the log header write buffer if (m_pDbHdrWriteBuf) { f_freeAlignedBuffer( (void **)&m_pDbHdrWriteBuf); } // Free the update buffer if (m_pucUpdBuffer) { f_free( &m_pucUpdBuffer); m_uiUpdBufferSize = 0; } m_krefPool.poolFree(); if (m_ppBlocksDone) { f_free( &m_ppBlocksDone); m_uiBlocksDoneArraySize = 0; } // Notify waiters that the F_Database is gone while (pCloseNotifies) { F_SEM hSem; *(pCloseNotifies->pRc) = NE_XFLM_OK; hSem = pCloseNotifies->hSem; pCloseNotifies = pCloseNotifies->pNext; f_semSignal( hSem); } f_free( &m_pszDbPath); // Encryption stuff if (m_pszDbPasswd) { f_free( &m_pszDbPasswd); } if (m_pWrappingKey) { m_pWrappingKey->Release(); m_pWrappingKey = NULL; } flmAssert( !m_pFirstNode && !m_pLastNode && !m_pLastDirtyNode); if (m_hMutex != F_MUTEX_NULL) { f_mutexDestroy( &m_hMutex); } // Global mutex is still expected to be locked at this point f_mutexLock( gv_XFlmSysData.hShareMutex); }
/**************************************************************************** Desc: Prints the web page showing the binary data in an SCache block ****************************************************************************/ RCODE F_SCacheDataPage::display( FLMUINT uiNumParams, const char ** ppszParams) { RCODE rc = FERR_OK; FLMUINT uiBlkAddress = 0; FLMUINT uiLowTransID = 0; FLMUINT uiHighTransID = 0; FFILE * pFile = NULL; FLMBOOL bFlaimLocked = FALSE; SCACHE LocalSCacheBlock; char * pucData = NULL; char * pucDataLine; char szData[97]; char szOneChar[7]; FLMUINT uiCurrentOffset = 0; FLMUINT uiLoop = 0; f_mutexLock( gv_FlmSysData.hShareMutex); bFlaimLocked = TRUE; rc = locateSCacheBlock( uiNumParams, ppszParams, &LocalSCacheBlock, &uiBlkAddress, &uiLowTransID, &uiHighTransID, &pFile); if (RC_BAD( rc)) { if(rc == FERR_NOT_FOUND) { notFoundErr(); rc = FERR_OK; } goto Exit; } else { // Store the data in a local variable... if( RC_BAD( rc = f_alloc( LocalSCacheBlock.ui16BlkSize, &pucData))) { goto Exit; } f_memcpy( pucData, LocalSCacheBlock.pucBlk, LocalSCacheBlock.ui16BlkSize); } f_mutexUnlock( gv_FlmSysData.hShareMutex); bFlaimLocked = FALSE; // Start the HTML... stdHdr(); fnPrintf( m_pHRequest, HTML_DOCTYPE "<HTML> <BODY>\n<font face=arial><PRE>\n"); while (uiCurrentOffset < LocalSCacheBlock.ui16BlkSize) { szData[0] = '\0'; pucDataLine = pucData + uiCurrentOffset; fnPrintf( m_pHRequest, "<font color=blue>0x%04X</font> " "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X ", uiCurrentOffset, pucDataLine[ 0], pucDataLine[ 1], pucDataLine[ 2], pucDataLine[ 3], pucDataLine[ 4], pucDataLine[ 5], pucDataLine[ 6], pucDataLine[ 7], pucDataLine[ 8], pucDataLine[ 9], pucDataLine[10], pucDataLine[11], pucDataLine[12], pucDataLine[13], pucDataLine[14], pucDataLine[15]); for (uiLoop = 0; uiLoop < 16; uiLoop++) { if ( (pucDataLine[uiLoop] >= 32) && // 32 is a space (pucDataLine[uiLoop] <= 126) ) // 126 is a ~ { f_sprintf( szOneChar, "&#%d;", pucDataLine[uiLoop]); } else { f_strcpy( szOneChar, "."); // 46 is a . } f_strcat(szData, szOneChar); // The reason for all the &#xxx; nonsence is because if we just put // the characters into a string, when the brower comes across a < // character, it will try to interpret what follows as an HTML // tag... } fnPrintf( m_pHRequest, "<font color=green>%s</font>\n", szData); uiCurrentOffset += 16; } fnPrintf( m_pHRequest, "</PRE></font>\n</BODY> </HTML>\n"); fnEmit(); Exit: if (bFlaimLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } if (pucData) { f_free( &pucData); } return( rc); }
/**************************************************************************** Desc: This routine links a request into a notification list and then waits to be notified that the event has occurred. The mutex is assumed to protect the notify list. ****************************************************************************/ RCODE FLMAPI f_notifyWait( F_MUTEX hMutex, F_SEM hSem, void * pvData, F_NOTIFY_LIST_ITEM ** ppNotifyList) { RCODE rc = NE_FLM_OK; RCODE tmpRc; F_NOTIFY_LIST_ITEM stackNotify; F_NOTIFY_LIST_ITEM * pNotify = &stackNotify; f_assertMutexLocked( hMutex); f_assert( pNotify != *ppNotifyList); f_memset( &stackNotify, 0, sizeof( F_NOTIFY_LIST_ITEM)); pNotify->uiThreadId = f_threadId(); pNotify->hSem = F_SEM_NULL; if( hSem == F_SEM_NULL) { if( RC_BAD( rc = f_semCreate( &pNotify->hSem))) { goto Exit; } } else { pNotify->hSem = hSem; } pNotify->pRc = &rc; pNotify->pvData = pvData; pNotify->pNext = *ppNotifyList; *ppNotifyList = pNotify; // Unlock the mutex and wait on the semaphore f_mutexUnlock( hMutex); if( RC_BAD( tmpRc = f_semWait( pNotify->hSem, F_WAITFOREVER))) { rc = tmpRc; } // Free the semaphore if( hSem != pNotify->hSem) { f_semDestroy( &pNotify->hSem); } // Relock the mutex f_mutexLock( hMutex); Exit: return( rc); }
/**************************************************************************** Desc: This routine performs all of the necessary steps to complete a create or open of a database, including notifying other threads waiting for the open or create to complete. NOTE: If RC_BAD( rc), this routine will delete the F_Db object. ****************************************************************************/ void F_Db::completeOpenOrCreate( RCODE rc, FLMBOOL bNewDatabase ) { if (RC_OK( rc)) { // If this is a newly created F_Database, we need to notify any // threads waiting for the database to be created or opened that // the create or open is now complete. if (bNewDatabase) { f_mutexLock( gv_XFlmSysData.hShareMutex); m_pDatabase->newDatabaseFinish( NE_XFLM_OK); f_mutexUnlock( gv_XFlmSysData.hShareMutex); } } else { F_Database * pDatabase = m_pDatabase; // Temporarily increment the open count on the F_Database structure // so that it will NOT be freed when pDb is freed below. if (bNewDatabase) { f_mutexLock( gv_XFlmSysData.hShareMutex); pDatabase->m_uiOpenIFDbCount++; f_mutexUnlock( gv_XFlmSysData.hShareMutex); } // NOTE: Cannot access this F_Db object after this! // Must do this before potentially deleting the F_Database object // below, so that the F_Db object will unlink itself from // the F_Database object. Release(); // If we allocated the F_Database object, notify any // waiting threads. if (bNewDatabase) { f_mutexLock( gv_XFlmSysData.hShareMutex); // Decrement the use count to compensate for the increment // that occurred above. pDatabase->m_uiOpenIFDbCount--; // If this is a newly created F_Database, we need to notify any // threads waiting for the database to be created or opened that // the create or open is now complete. pDatabase->newDatabaseFinish( rc); pDatabase->freeDatabase(); f_mutexUnlock ( gv_XFlmSysData.hShareMutex); } } }