void CheckpointDaemon::run() { std::cout << "CheckpointDaemon started..." << std::endl; // bind to numa node bindCurrentThreadToNumaNode(0); struct timeval time_start, time_cur; unsigned long long elapsed_usec; gettimeofday(&time_start, NULL); std::chrono::milliseconds check_interval(500); while (_running) { std::this_thread::sleep_for(check_interval); gettimeofday(&time_cur, NULL); elapsed_usec = (time_cur.tv_sec * 1000000 + time_cur.tv_usec) - (time_start.tv_sec * 1000000 + time_start.tv_usec); if (elapsed_usec > _checkpointing_interval_in_ms * 1000) { doCheckpoint(); time_start = time_cur; } } }
/**************************************************************************** Desc: Set the RFL keep files flag. ****************************************************************************/ RCODE XFLAPI F_Db::setRflKeepFilesFlag( FLMBOOL bKeepFiles) { RCODE rc = NE_XFLM_OK; FLMBOOL bDbLocked = FALSE; // See if the database is being forced to close if (RC_BAD( rc = checkState( __FILE__, __LINE__))) { goto Exit; } // Make sure we don't have a transaction going if (m_eTransType != XFLM_NO_TRANS) { rc = RC_SET( NE_XFLM_TRANS_ACTIVE); goto Exit; } // Make sure there is no active backup running m_pDatabase->lockMutex(); if (m_pDatabase->m_bBackupActive) { m_pDatabase->unlockMutex(); rc = RC_SET( NE_XFLM_BACKUP_ACTIVE); goto Exit; } m_pDatabase->unlockMutex(); // Need to lock the database but not start a transaction yet. if (!(m_uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) { if (RC_BAD( rc = dbLock( FLM_LOCK_EXCLUSIVE, 0, FLM_NO_TIMEOUT))) { goto Exit; } bDbLocked = TRUE; } // If we aren't changing the keep flag, jump to exit without doing // anything. if ((bKeepFiles && m_pDatabase->m_lastCommittedDbHdr.ui8RflKeepFiles) || (!bKeepFiles && !m_pDatabase->m_lastCommittedDbHdr.ui8RflKeepFiles)) { goto Exit; // Will return NE_XFLM_OK; } // Force a checkpoint and roll to the next RFL file numbers. // When changing from keep to no-keep or vice versa, we need to // go to a new RFL file so that the new RFL file gets new // serial numbers and a new keep or no-keep flag. if (RC_BAD( rc = doCheckpoint( FLM_NO_TIMEOUT))) { goto Exit; } f_memcpy( &m_pDatabase->m_uncommittedDbHdr, &m_pDatabase->m_lastCommittedDbHdr, sizeof( XFLM_DB_HDR)); m_pDatabase->m_uncommittedDbHdr.ui8RflKeepFiles = (FLMUINT8)(bKeepFiles ? (FLMUINT8)1 : (FLMUINT8)0); // Force a new RFL file - this will also write out the entire // log header - including the changes we made above. if (RC_BAD( rc = m_pDatabase->m_pRfl->finishCurrFile( this, TRUE))) { goto Exit; } Exit: if (bDbLocked) { dbUnlock(); } return( rc); }
/**************************************************************************** Desc: Set the RFL directory for a database. ****************************************************************************/ RCODE XFLAPI F_Db::setRflDir( const char * pszNewRflDir) { RCODE rc = NE_XFLM_OK; FLMBOOL bDbLocked = FALSE; // See if the database is being forced to close if (RC_BAD( rc = checkState( __FILE__, __LINE__))) { goto Exit; } // Make sure we don't have a transaction going if (m_eTransType != XFLM_NO_TRANS) { rc = RC_SET( NE_XFLM_TRANS_ACTIVE); goto Exit; } // Make sure there is no active backup running m_pDatabase->lockMutex(); if (m_pDatabase->m_bBackupActive) { m_pDatabase->unlockMutex(); rc = RC_SET( NE_XFLM_BACKUP_ACTIVE); goto Exit; } m_pDatabase->unlockMutex(); // Make sure the path exists and that it is a directory // rather than a file. if (pszNewRflDir && *pszNewRflDir) { if (!gv_XFlmSysData.pFileSystem->isDir( pszNewRflDir)) { rc = RC_SET( NE_FLM_IO_INVALID_FILENAME); goto Exit; } } // Need to lock the database because we can't change the RFL // directory until after the checkpoint has completed. The // checkpoint code will unlock the transaction, but not the // file if we have an explicit lock. We need to do this to // prevent another transaction from beginning before we have // changed the RFL directory. if (!(m_uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) { if( RC_BAD( rc = dbLock( FLM_LOCK_EXCLUSIVE, 0, FLM_NO_TIMEOUT))) { goto Exit; } bDbLocked = TRUE; } // Force a checkpoint and roll to the next RFL file numbers. Both // of these steps are necessary to ensure that we won't have to do // any recovery using the current RFL file - because we do not // move the current RFL file to the new directory. Forcing the // checkpoint ensures that we have no transactions that will need // to be recovered if we were to crash. Rolling the RFL file number // ensures that no more transactions will be logged to the current // RFL file. if (RC_BAD( rc = doCheckpoint( FLM_NO_TIMEOUT))) { goto Exit; } // Force a new RFL file. if (RC_BAD( rc = m_pDatabase->m_pRfl->finishCurrFile( this, FALSE))) { goto Exit; } // Set the RFL directory to the new value now that we have // finished the checkpoint and rolled to the next RFL file. m_pDatabase->lockMutex(); rc = m_pDatabase->m_pRfl->setRflDir( pszNewRflDir); m_pDatabase->unlockMutex(); Exit: if (bDbLocked) { dbUnlock(); } return( rc); }
/**************************************************************************** Desc: Try to perform a checkpoint on the database. Returns TRUE if we need to terminate. ****************************************************************************/ FLMBOOL F_Database::tryCheckpoint( IF_Thread * pThread, CP_INFO * pCPInfo) { RCODE rc = NE_XFLM_OK; FLMBOOL bTerminate = FALSE; FLMBOOL bForceCheckpoint; FLMINT iForceReason; FLMUINT uiCurrTime; XFLM_DB_STATS * pDbStats; // See if we should terminate the thread. if (pThread->getShutdownFlag()) { // Set terminate flag to TRUE and then see if // we have been set up to do one final checkpoint // to flush dirty buffers to disk. bTerminate = TRUE; } // Determine if we need to force a checkpoint. bForceCheckpoint = FALSE; iForceReason = 0; uiCurrTime = (FLMUINT)FLM_GET_TIMER(); if (bTerminate) { bForceCheckpoint = TRUE; iForceReason = XFLM_CP_SHUTTING_DOWN_REASON; } else if (!m_pRfl->seeIfRflVolumeOk() || RC_BAD( m_CheckpointRc)) { bForceCheckpoint = TRUE; iForceReason = XFLM_CP_RFL_VOLUME_PROBLEM; } else if ((FLM_ELAPSED_TIME( uiCurrTime, m_uiLastCheckpointTime) >= gv_XFlmSysData.uiMaxCPInterval) || (!gv_XFlmSysData.uiMaxCPInterval)) { bForceCheckpoint = TRUE; iForceReason = XFLM_CP_TIME_INTERVAL_REASON; } if (gv_XFlmSysData.Stats.bCollectingStats) { // Statistics are being collected for the system. Therefore, // if we are not currently collecting statistics in the // start. If we were collecting statistics, but the // start time was earlier than the start time in the system // statistics structure, reset the statistics. if (!pCPInfo->Stats.bCollectingStats) { flmStatStart( &pCPInfo->Stats); } else if (pCPInfo->Stats.uiStartTime < gv_XFlmSysData.Stats.uiStartTime) { flmStatReset( &pCPInfo->Stats, FALSE); } (void)flmStatGetDb( &pCPInfo->Stats, this, 0, &pDbStats, NULL, NULL); } else { pDbStats = NULL; } // Lock write object - If we are forcing a checkpoint // wait until we get the lock. Otherwise, if we can't get // the lock without waiting, don't do anything. if (bForceCheckpoint || (gv_XFlmSysData.pBlockCacheMgr->m_uiMaxDirtyCache && (m_uiDirtyCacheCount + m_uiLogCacheCount) * m_uiBlockSize > gv_XFlmSysData.pBlockCacheMgr->m_uiMaxDirtyCache)) { if (RC_BAD( rc = dbWriteLock( pCPInfo->hWaitSem, pDbStats))) { // THIS SHOULD NEVER HAPPEN BECAUSE dbWriteLock will // wait forever for the lock! RC_UNEXPECTED_ASSERT( rc); goto Exit; } pThread->setThreadStatusStr( "Forcing checkpoint"); // Must wait for any RFL writes to complete. (void)m_pRfl->seeIfRflWritesDone( pCPInfo->hWaitSem, TRUE); } else { if (RC_BAD( dbWriteLock( pCPInfo->hWaitSem, pDbStats, 0))) { goto Exit; } pThread->setThreadStatus( FLM_THREAD_STATUS_RUNNING); // See if we actually need to do the checkpoint. If the // current transaction ID and the last checkpoint transaction // ID are the same, no updates have occurred that would require // a checkpoint to take place. if (m_lastCommittedDbHdr.ui64RflLastCPTransID == m_lastCommittedDbHdr.ui64CurrTransID || !m_pRfl->seeIfRflWritesDone( pCPInfo->hWaitSem, FALSE)) { dbWriteUnlock(); goto Exit; } } // Do the checkpoint. (void)doCheckpoint( pCPInfo->hWaitSem, pDbStats, pCPInfo->pSFileHdl, FALSE, bForceCheckpoint, iForceReason, 0, 0); if (pDbStats) { (void)flmStatUpdate( &pCPInfo->Stats); } dbWriteUnlock(); // Set the thread's status pThread->setThreadStatus( FLM_THREAD_STATUS_SLEEPING); Exit: return( bTerminate); }