/**************************************************************************** Desc: Thread that will delete block chains from deleted indexes and tables in the background. ****************************************************************************/ RCODE SQFAPI F_Database::maintenanceThread( IF_Thread * pThread) { RCODE rc = NE_SFLM_OK; F_Database * pDatabase = (F_Database *)pThread->getParm1(); F_Db * pDb; F_Row * pRow; FLMUINT64 ui64MaintRowId; FLMBOOL bStartedTrans; FLMBOOL bShutdown; F_DbSystem * pDbSystem; FSTableCursor * pTableCursor; FLMUINT uiBlkAddress; FLMBOOL bIsNull; FLMUINT uiBlocksToFree; FLMUINT uiBlocksFreed; Retry: rc = NE_SFLM_OK; pDb = NULL; pRow = NULL; bStartedTrans = FALSE; bShutdown = FALSE; pDbSystem = NULL; pTableCursor = NULL; if( (pDbSystem = f_new F_DbSystem) == NULL) { rc = RC_SET( NE_SFLM_MEM); goto Exit; } pThread->setThreadStatus( FLM_THREAD_STATUS_INITIALIZING); if( RC_BAD( rc = pDbSystem->internalDbOpen( pDatabase, &pDb))) { // If the file is being closed, this is not an error. if( pDatabase->getFlags() & DBF_BEING_CLOSED) { rc = NE_SFLM_OK; bShutdown = TRUE; } goto Exit; } pDbSystem->Release(); pDbSystem = NULL; if ((pTableCursor = f_new FSTableCursor) == NULL) { rc = RC_SET( NE_SFLM_MEM); goto Exit; } for( ;;) { pThread->setThreadStatus( FLM_THREAD_STATUS_RUNNING); if( RC_BAD( rc = pDb->beginBackgroundTrans( pThread))) { goto Exit; } bStartedTrans = TRUE; pTableCursor->resetCursor(); if (RC_BAD( rc = pTableCursor->setupRange( pDb, SFLM_TBLNUM_BLOCK_CHAINS, 1, FLM_MAX_UINT64, FALSE))) { goto Exit; } // Free up to 25 blocks per transaction. uiBlocksToFree = 25; while (uiBlocksToFree) { if (RC_BAD( rc = pTableCursor->nextRow( pDb, &pRow, &ui64MaintRowId))) { if (rc != NE_SFLM_EOF_HIT) { RC_UNEXPECTED_ASSERT( rc); goto Exit; } rc = NE_SFLM_OK; break; } if (RC_BAD( rc = pRow->getUINT( pDb, SFLM_COLNUM_BLOCK_CHAINS_BLOCK_ADDRESS, &uiBlkAddress, &bIsNull))) { goto Exit; } if (bIsNull) { rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR); goto Exit; } if( RC_BAD( rc = pDb->maintBlockChainFree( ui64MaintRowId, uiBlkAddress, uiBlocksToFree, 0, &uiBlocksFreed))) { goto Exit; } uiBlocksToFree -= uiBlocksFreed; } bStartedTrans = FALSE; if( RC_BAD( rc = pDb->commitTrans( 0, FALSE))) { goto Exit; } pThread->setThreadStatus( FLM_THREAD_STATUS_SLEEPING); f_semWait( pDatabase->m_hMaintSem, F_WAITFOREVER); if (pThread->getShutdownFlag()) { bShutdown = TRUE; goto Exit; } } Exit: pThread->setThreadStatus( FLM_THREAD_STATUS_TERMINATING); if (pDbSystem) { pDbSystem->Release(); } if (pRow) { pRow->ReleaseRow(); } if( bStartedTrans) { pDb->abortTrans(); } if (pDb) { pDb->Release(); pDb = NULL; } if (!bShutdown) { flmAssert( RC_BAD( rc)); f_sleep( 250); f_semSignal( pDatabase->m_hMaintSem); goto Retry; } 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); }