FINLINE void FTKAPI setThreadAppId( FLMUINT uiAppId) { f_mutexLock( m_hMutex); m_uiAppId = uiAppId; f_mutexUnlock( m_hMutex); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogWrite( F_Database * pDatabase, FLMUINT uiBlkAddress, FLMUINT uiWriteAddress, FLMUINT64 ui64TransId, char * pszEvent) { char pszTmpBuf[ 256]; if( !g_bDbgLogEnabled) return; if( !uiWriteAddress) { f_sprintf( (char *)pszTmpBuf, "d%X b=%X t%I64u %s", (unsigned)((FLMUINT)pDatabase), (unsigned)uiBlkAddress, ui64TransId, pszEvent); } else { f_sprintf( (char *)pszTmpBuf, "d%X b=%X a=%X t%I64u %s", (unsigned)((FLMUINT)pDatabase), (unsigned)uiBlkAddress, (unsigned)uiWriteAddress, ui64TransId, pszEvent); } f_mutexLock( g_hDbgLogMutex); _flmDbgOutputMsg( pszTmpBuf); f_mutexUnlock( g_hDbgLogMutex); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogExit( void) { if( g_bDbgLogEnabled) { // Output "Log End" message f_mutexLock( g_hDbgLogMutex); _flmDbgOutputMsg( "--- LOG END ---"); f_mutexUnlock( g_hDbgLogMutex); // Flush the log flmDbgLogFlush(); } // Free all resources if( g_hDbgLogMutex != F_MUTEX_NULL) { f_mutexDestroy( &g_hDbgLogMutex); } if( g_pszLogBuf) { f_free( &g_pszLogBuf); } if( g_pLogFile) { g_pLogFile->Truncate( g_uiLogFileOffset + g_uiLogBufOffset); g_pLogFile->Close(); g_pLogFile->Release(); g_pLogFile = NULL; } g_bDbgLogEnabled = FALSE; }
/******************************************************************** Desc: Output a label in the LABEL_COLUMN *********************************************************************/ void gigaOutputLabel( FLMUINT uiRow, const char * pszLabel, FLMBOOL bMutexLocked) { char szLabel [DATA_COLUMN - LABEL_COLUMN]; char * pszTmp; FLMUINT uiNumDots = sizeof( szLabel) - 1; f_memset( szLabel, '.', uiNumDots); szLabel [uiNumDots] = 0; pszTmp = &szLabel [0]; uiNumDots -= 2; while( *pszLabel && uiNumDots) { *pszTmp++ = (FLMBYTE)(*pszLabel++); uiNumDots--; } if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexLock( gv_hWindowMutex); } FTXWinPrintStrXY( gv_pWindow, szLabel, LABEL_COLUMN, uiRow); if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexUnlock( gv_hWindowMutex); } }
/**************************************************************************** Desc: Event callback *****************************************************************************/ void IX_Event::catchEvent( eEventType eEvent, IF_Db * pDb, FLMUINT, // uiThreadId, FLMUINT64, // ui64TransID, FLMUINT uiIndexOrCollection, FLMUINT64 ui64NodeId, RCODE // rc ) { XFLM_INDEX_STATUS ixStatus; FLMUINT uiGMT; if (eEvent == XFLM_EVENT_INDEXING_PROGRESS && !ui64NodeId && pDb) { if (RC_OK( ((F_Db *)pDb)->indexStatus( uiIndexOrCollection, &ixStatus))) { f_timeGetSeconds( &uiGMT ); f_mutexLock( m_pDispInfo->hScreenMutex); FTXWinPrintf( m_pDispInfo->pLogWin, "Index %u came on-line. Elapsed time = %u second(s)\n", uiIndexOrCollection, uiGMT - (FLMUINT)ixStatus.ui32StartTime); f_mutexUnlock( m_pDispInfo->hScreenMutex); } } }
/**************************************************************************** Desc: ****************************************************************************/ void F_IOBuffer::notifyComplete( RCODE completionRc) { f_assert( m_bPending); m_bPending = FALSE; m_bCompleted = TRUE; m_completionRc = completionRc; m_uiEndTime = FLM_GET_TIMER(); m_uiElapsedTime = FLM_TIMER_UNITS_TO_MILLI( FLM_ELAPSED_TIME( m_uiEndTime, m_uiStartTime)); if( m_fnCompletion) { m_fnCompletion( this, m_pvData); m_fnCompletion = NULL; m_pvData = NULL; } 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); if( RC_OK( m_pBufferMgr->m_completionRc) && RC_BAD( completionRc)) { m_pBufferMgr->m_completionRc = completionRc; } f_mutexUnlock( m_pBufferMgr->m_hMutex); } }
/**************************************************************************** Desc: ****************************************************************************/ RCODE FTKAPI F_IOBufferMgr::waitForAllPendingIO( void) { RCODE rc = NE_FLM_OK; RCODE tmpRc; F_IOBuffer * pBuf; FLMBOOL bMutexLocked = FALSE; f_mutexLock( m_hMutex); bMutexLocked = TRUE; while( (pBuf = m_pFirstPending) != NULL) { pBuf->AddRef(); f_mutexUnlock( m_hMutex); bMutexLocked = FALSE; if( RC_BAD( tmpRc = pBuf->waitToComplete())) { if( RC_OK( m_completionRc)) { f_mutexLock( m_hMutex); bMutexLocked = TRUE; m_completionRc = tmpRc; } } if( !bMutexLocked) { f_mutexLock( m_hMutex); bMutexLocked = TRUE; } pBuf->Release( TRUE); pBuf = NULL; } rc = m_completionRc; m_completionRc = NE_FLM_OK; if( bMutexLocked) { f_mutexUnlock( m_hMutex); } return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void flmDbgLogMsg( char * pszMsg) { if (!g_bDbgLogEnabled) return; f_mutexLock( g_hDbgLogMutex); _flmDbgOutputMsg( pszMsg); f_mutexUnlock( g_hDbgLogMutex); }
/******************************************************************** Desc: Show help for the gigaloader. *********************************************************************/ void gigaShowHelp( void) { #ifdef FLM_NLM if (!gv_bSynchronized) { SynchronizeStart(); gv_bSynchronized = TRUE; } #endif f_mutexLock( gv_hWindowMutex); FTXWinClear( gv_pWindow); FTXWinPrintStr( gv_pWindow, "\n"); FTXWinPrintStr( gv_pWindow, "Parameters: [Number To Create] [Options]\n\n"); FTXWinPrintStr( gv_pWindow, "\nNumber To Create\n"); FTXWinPrintStr( gv_pWindow, " Number of object to create (default = 100,000)\n"); FTXWinPrintStr( gv_pWindow, "\nOptions (may be specified anywhere on command line):\n"); FTXWinPrintStr( gv_pWindow, " -b = Run in batch mode.\n"); FTXWinPrintStr( gv_pWindow, " -c<n> = Cache (bytes) to use, 0=Use default mode\n"); FTXWinPrintStr( gv_pWindow, " -p<n> = Block cache percentage (0-100) to use (default 50)\n"); FTXWinPrintStr( gv_pWindow, " -i<n> = Checkpoint interval (seconds) to use.\n"); #ifdef FLM_NLM FTXWinPrintStr( gv_pWindow, " -n<DbName> = Database name (default = sys:\\_netware\\gigatest.db).\n"); #else FTXWinPrintStr( gv_pWindow, " -n<DbName> = Database name (default = gigatest.db).\n"); #endif FTXWinPrintStr( gv_pWindow, " -dr<Dir> = Directory where rfl files are located (default=same as db)\n"); FTXWinPrintStr( gv_pWindow, " -dd<Dir> = Directory where data files are located (default=same as db)\n"); FTXWinPrintStr( gv_pWindow, " -t<n> = Transaction Size (objects per transaction, default=100).\n"); #ifdef FLM_NLM FTXWinPrintStr( gv_pWindow, " -w = Wait to end to synchronize\n"); #endif FTXWinPrintStr( gv_pWindow, " -md<n> = Set maximum dirty cache (bytes), 0=Use default mode\n"); FTXWinPrintStr( gv_pWindow, " -ld<n> = Set low dirty cache (bytes), default=0\n"); FTXWinPrintStr( gv_pWindow, " -? = A '?' anywhere in the command line will cause this help\n"); FTXWinPrintStr( gv_pWindow, " screen to be displayed, with or without the leading '-'.\n"); f_mutexUnlock( gv_hWindowMutex); gigaOutputErrMsg( ""); }
/****************************************************************** Desc: Implements the addChar function of the DynamicBuffer class *******************************************************************/ RCODE F_DynamicBuffer::addChar( char ucCharacter) { RCODE rc = FERR_OK; if (!m_bSetup) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } f_mutexLock( m_hMutex); // Is there room for just one more character plus a terminator? if ((m_uiBuffSize - m_uiUsedChars) > 1) { m_pucBuffer[ m_uiUsedChars++] = ucCharacter; m_pucBuffer[ m_uiUsedChars] = 0; } else { // Allocate a new buffer or increase the size of the existing one. if( !m_uiBuffSize) { if( RC_BAD( rc = f_alloc( 50, &m_pucBuffer))) { goto Exit; } m_uiBuffSize = 50; } else { if( RC_BAD( rc = f_realloc( m_uiBuffSize + 50, &m_pucBuffer))) { goto Exit; } m_uiBuffSize += 50; } m_pucBuffer[ m_uiUsedChars++] = ucCharacter; m_pucBuffer[ m_uiUsedChars] = 0; } Exit: if ( m_bSetup) { f_mutexUnlock( m_hMutex); } return( rc); }
/******************************************************************** Desc: Checks to see if the user pressed ESCAPE to exit the loader. Also updates the total loaded counter on the screen. *********************************************************************/ FLMUINT gigaSeeIfQuit( void) { FLMUINT uiChar = 0;; f_mutexLock( gv_hWindowMutex); gigaOutputUINT( TOTAL_LOADED_ROW, gv_uiTotalLoaded, TRUE); if (RC_OK( FTXWinTestKB( gv_pWindow))) { FTXWinInputChar( gv_pWindow, &uiChar); if (uiChar == FKB_ESCAPE) { uiChar = gigaGetInput( "ESCAPE pressed, quit? (ESC,Q,Y=Quit, other=continue): ", NULL, TRUE); switch (uiChar) { case 'Q': case 'q': case 'y': case 'Y': uiChar = FKB_ESCAPE; break; case FKB_ESCAPE: break; default: uiChar = 0; break; } } else if( uiChar == 'i' || uiChar == 'I') { HFDB hDb; f_threadDestroy( &gv_pIxManagerThrd); if (RC_OK( FlmDbOpen( gv_szDibName, gv_szDataDir, gv_szRflDir, 0, NULL, &hDb))) { f_threadCreate( &gv_pIxManagerThrd, flstIndexManagerThread, "index_manager", F_DEFAULT_THREAD_GROUP, 0, (void *)hDb); } } } if (gv_bShutdown) { uiChar = FKB_ESCAPE; } f_mutexUnlock( gv_hWindowMutex); return( uiChar); }
/**************************************************************************** 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: ****************************************************************************/ 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: ****************************************************************************/ 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_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: 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: *********************************************************************/ 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: ****************************************************************************/ 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 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 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: ****************************************************************************/ void flmDbgLogFlush( void) { f_mutexLock( g_hDbgLogMutex); _flmDbgLogFlush(); f_mutexUnlock( g_hDbgLogMutex); }
/**************************************************************************** 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: 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: 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); }