#include "ReplicateThread.h" #include #include #include #include "Logger.h" #include "FtsdSocketControl.h" #include "ServiceConfig.h" #include "ReportLog.h" // ftsd ·Î ºÎÅÍ Ã³¸® °á°ú ¼ö½ÅÀ» À§ÇÑ Total ´ë±â ½Ã°£ Á¤ÀÇ ( sec ) #define FHS_RESPONSE_TOTAL_TIMEOUT 3600 // ( sec, 1 hour ) // ftsd ·Î ºÎÅÍ ÀÀ´ä ¼ö½Å È®ÀÎÀ» À§ÇÑ socket read timeout (sec) #define FHS_RESPONSE_CHECK_TIMEOUT 3 // 3 sec //////////////////////////////////////////// // »ý¼ºÀÚ CReplicateThread::CReplicateThread( CProcessStatus* const pProcessStatus , CDataQueue* const pQueueRetry , CDataQueue* const pQueueComplete , CRetryData& dataJob , std::vector& vecTargetFHS ) : m_pProcessStatus( pProcessStatus ) , m_pRetryQueue( pQueueRetry ) , m_pCompleteQueue( pQueueComplete ) , m_dataJob( dataJob ) , m_vecTargetFHS( vecTargetFHS ) { // ¸â¹ö º¯¼ö ÃʱâÈ­ m_threadHandle = 0; } // ¼Ò¸êÀÚ CReplicateThread::~CReplicateThread() { // Thread µ¿ÀÛ Á¤Áö ó¸® // - ¸¸¾à Thread °¡ ÀÌ¹Ì Á¾·áµÈ °æ¿ì m_threadHandle ÀÌ ´Ù¸¥ Thread Handle ÀÏ ¼ö ÀÖÀ¸¹Ç·Î // ¾÷¹« Flow ¼öÁ¤½Ã ÁÖÀÇÇÒ °Í if( m_threadHandle != 0 ) pthread_cancel( m_threadHandle ); } // ½ÇÁ¦ Replication »ý¼º ÀÛ¾÷À» ¼öÇà bool CReplicateThread::Start() { int nRet = ::pthread_create( &m_threadHandle, NULL, CReplicateThread::threadFunc, this ); if( nRet != 0 ) { // Thread »ý¼º ½ÇÆÐ½Ã int errorNum = errno; LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) ); return false; } return true; } // ½º·¹µå ÇÔ¼ö void* CReplicateThread::threadFunc( void* arg ) { CReplicateThread* pObject = reinterpret_cast( arg ); pthread_detach( pthread_self() ); pthread_testcancel(); // Thread µ¿À۽à Thread Count 1 Áõ°¡ ó¸® pObject->m_pProcessStatus->AddReplicationCount(); // ½ÇÁ¦ ÀÛ¾÷ ¼öÇà. pObject->Execute(); // Thread µ¿ÀÛ ¿Ï·á½Ã Thread Count 1 °¨¼Ò ó¸® pObject->m_pProcessStatus->SubtractReplicationCount(); pthread_testcancel(); // NEW 2014-06-25 huibong // Thread Á¾·á½Ã m_threadHandle °ªÀ» ÃʱâÈ­ ó¸®. // - ¼Ò¸êÀÚ¿¡¼­ À߸øµÈ Thread ¸¦ Á¾·áÇÒ ¼ö Àֱ⠶§¹®. pObject->m_threadHandle = 0; // °´Ã¼ ÀÚµ¿ delete ó¸®. delete pObject; return NULL; } // ½ÇÁ¦ Replication »ý¼º ÀÛ¾÷À» ¼öÇà void CReplicateThread::Execute() { // 1. FHS ÀÇ ftsd ¿Í Åë½Å 󸮸¦ ´ã´çÇÒ socket control °´Ã¼ »ý¼º. CFtsdSocketControl fhs; // 2. ¿øº» Content¸¦ °¡Áø FHS ftsd ¿¡ Á¢¼Ó ¼öÇà. bool bResult = fhs.ConnectTarget( m_dataJob.m_OriginData.m_szOriginHostName, CServiceConfig::GetInstance()->GetFhsTransferDaemonPort()); if( bResult == false ) { // ¿øº» FHS ¿Í Á¢¼Ó ½ÇÆÐ½Ã // - ·Î±ë ÈÄ Retry Queue ¿¡ ÀúÀå ó¸® _LOG( LERR, "CReplicateThread: source fhs[%s] connect fail.[%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoFailProcess(); return; } // 3. ¿¬°áµÈ ¿øº» FHS ·Î replication »ý¼º ¿äûÀ» Àü´Þ bResult = fhs.SendFileReplicationRequest( m_dataJob.m_OriginData.m_szFileNameHash , m_dataJob.m_OriginData.m_nContentLength , CServiceConfig::GetInstance()->GetHashCheckLevel() , true , m_vecTargetFHS ); if( bResult == false ) { // replication ¿äû Àü´Þ ½ÇÆÐ½Ã // - ·Î±ë ÈÄ Retry Queue ¿¡ ÀúÀå ó¸® _LOG( LERR, "CReplicateThread: replication request send fail.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoFailProcess(); return; } // 4. FHS ·Î ºÎÅÍ Ã³¸® °á°ú¸¦ ¼ö½ÅÇÒ¶§ ±îÁö ´ë±â // - ÀÌ»ó »óȲ ¹ß»ý½Ã ¹«ÇÑ ´ë±â °¡´É¼ºÀÌ Á¸ÀçÇϹǷÎ.. // ¹Ì¸® Á¤ÀÇµÈ FHS_RESPONSE_TOTAL_TIMEOUT ±îÁö¸¸ ´ë±âÇϵµ·Ï ÇÑ´Ù. // response timeout 󸮸¦ À§ÇÑ º¯¼ö time_t timeStart; time_t timeNow; // ÀÀ´ä °á°ú¸¦ ÀúÀåÇϱâ À§ÇÑ º¯¼ö int nResult; bool bSuccess = false; std::string szErrorMessage; // ´ë±â ½ÃÀÛ Àü ÇöÀç½Ã°£À» ±¸ÇÑ´Ù. timeStart = time( &timeStart ); // FHS ·Î ºÎÅÍ ÀÀ´ä ¼ö½Å ´ë±â while( 1 ) { // FHS ·Î ºÎÅÍ ÀÀ´ä ¼ö½Å ó¸® // -1 : ¿¬°á Á¾·á // 0 : Timeout ¹ß»ý // 1 : ÀÀ´ä ¼ö½Å // 2 : º¹Á¦ °ü·Ã ÀÀ´äÀÌ ¾Æ´Ñ ´Ù¸¥ ÀÀ´äÀÎ °æ¿ì.. (¹ß»ýÇÏÁö ¾ÊÁö¸¸.. Ȥ½Ã³ª) nResult = fhs.GetFileReplicationResult( FHS_RESPONSE_CHECK_TIMEOUT , bSuccess , szErrorMessage , m_mapSuccessFhs , m_mapFailFhs ); if( nResult == 0 ) { // ÁöÁ¤µÈ ½Ã°£µ¿¾È ÀÀ´ä °á°ú¸¦ ¼ö½ÅÇÏÁö ¸øÇÑ °æ¿ì // - FHS ¿Í ¿¬°áÀÌ Á¤»óÀÎÁö Alive üũ È£Ãâ // - ¸¸¾à ¿¬°áÀÌ ³¡¾îÁø °æ¿ì.. ´ÙÀ½ loop ¿¡¼­ -1 ¿¬°á Á¾·á°¡ ¸®ÅϵÊ. if( fhs.SendAliveCheck() == false ) { _LOG( LERR, "CReplicateThread: alive check fail.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); } // Timeout ÀÌ ¹ß»ýÇßÀ¸¹Ç·Î ¹Ù·Î Àç½ÃµµÇÏÁö ¾Ê°í Á¶±Ý ´ë±â ÈÄ ´Ù½Ã ½Ãµµ. sleep( 1 ); } else if( nResult == 1 ) { // FHS ·Î ºÎÅÍ ÀÀ´äÀ» ¼ö½ÅÇÑ °æ¿ì. // - Content ÀÌ»óÀ¸·Î ÀÎÇØ Àü¼Û ÀÚü¸¦ ÇÏÁö ¸øÇß´ÂÁö ¿©ºÎ ÆÇ´Ü if( bSuccess == true ) { // Á¤»óÀûÀ¸·Î Replication ÀÌ Ã³¸®µÈ °æ¿ì.. _LOG( LDBG, "CReplicateThread: result receive.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoSuccessProcess(); } else { // Content ÀÌ»óÀ¸·Î ÀÎÇØ Replication ÀÚü¿¡ ¹®Á¦°¡ ÀÖ´Â °æ¿ì. _LOG( LERR, "CReplicateThread: error result receive.[%s][%s][%s][%llu]" , szErrorMessage.c_str() , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() , m_dataJob.m_OriginData.m_nContentLength ); DoErrorProcess( szErrorMessage ); } // ó¸® °á°ú¸¦ ¼ö½ÅÇßÀ¸¹Ç·Î loop Á¾·á. break; } else if( nResult == -1 ) { // FHS ¿Í ¿¬°áÀÌ ³¡¾îÁø °æ¿ì. // - retry queue ¿¡ ÀúÀåÇÏ°í º» ·çÇÁ´Â Á¾·á _LOG( LERR, "CReplicateThread: fhs connection broken.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoFailProcess(); break; } else if( nResult == 2 ) { // Replication °ü·Ã ÀÀ´äÀÌ ¾Æ´Ñ °æ¿ì // - ¹«½Ã ; } else { // ±âŸ Á¤ÀǵÇÁö ¾ÊÀº °á°ú°ª ¹Ýȯ½Ã // - FHS ¿Í ¼¼¼Ç ÀÌ»óÀÌ ¹ß»ýÇÒ ¼ö ÀÖÀ¸¹Ç·Î // - ½ÇÆÐ·Î ó¸®ÇÏ¿© retry queue ¿¡ ÀúÀåÇÏ°í º» ·çÇÁ´Â Á¾·á _LOG( LERR, "CReplicateThread: receive undefine result.[%d][%s][%s]" , nResult , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoFailProcess(); break; } // Total Reponse ´ë±â ½Ã°£ È®ÀÎ if( difftime( time( &timeNow ), timeStart ) > FHS_RESPONSE_TOTAL_TIMEOUT ) { // Total Response Timeout ¹ß»ý½Ã // - ·Î±ë ÈÄ Retry Queue ¿¡ ÀúÀå ó¸® // - º» ´ë±â ·çÇÁ¸¦ Á¾·á _LOG( LERR, "CReplicateThread: replication result receive timeout.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); DoFailProcess(); break; } } // while( 1 ) } // Replication ó¸® °ü·Ã ¿À·ù°¡ ¹ß»ýÇÑ °æ¿ì ó¸® ÇÔ¼ö. // - Àç½Ãµµ Ƚ¼ö¸¦ È®ÀÎÇÏ¿© // - Retry queue ¿¡ ÀúÀå ó¸® void CReplicateThread::DoFailProcess() { // Àç½Ãµµ Ƚ¼ö Ãʰú ¿©ºÎ È®ÀÎ. if( m_dataJob.m_uFailCount + 1 > CServiceConfig::GetInstance()->GetMaxRetryCount() ) { // Àç½Ãµµ Ƚ¼ö Ãʰú½Ã // - Report ·Î±×¿¡ ±â·ÏÇϰí Retry Queue ¿¡´Â ÀúÀåÇÏÁö ¾Ê´Â´Ù. _LOG( LERR, "CReplicateThread: replicate thread fail and retry count over.[%s][%s]" , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); CReportLog reportLog; if( reportLog.Init( CServiceConfig::GetInstance()->GetLogPath() ) == false ) { std::string strErrorMessage; reportLog.GetLastError( strErrorMessage ); LOG( LERR, "report log init fail. [%s]", strErrorMessage.c_str() ); } else { reportLog.Write( "ERR", "[%s][Replication fail. check content[%s][%s]]" , PROG_NAME , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() ); } } else { // Retry Queue ¿¡ ÀúÀå ó¸®. m_dataJob.m_uFailCount += 1; m_dataJob.m_timeFailed = time( 0 ); // Retry Queue °¡ Full ÀÎ »óÅ¿¡¼­ // ÀÛ¾÷ Thread °¡ ¸ðµÎ Push »óÅÂÀÎ °æ¿ì ¹«ÇÑ Block »óÅ ¹ß»ý °¡´É... // ÇÏÁö¸¸.. ½ÇÁ¦ ¹ß»ý °¡´ÉÀÌ Èñ¹ÚÇϹǷÎ... ¹«ÇÑ Àç½Ãµµ ó¸®. while( m_pRetryQueue->Push( m_dataJob ) == false ) { sleep( 1 ); } } return; } // Replication 󸮿¡ ´ëÇØ FHS ¿¡¼­ ½ÇÆÐ·Î ÀÀ´äÇÑ °æ¿ì. // - ´ëºÎºÐ Replication ´ë»ó content °¡ Á¸ÀçÇÏÁö ¾Ê°Å³ª Size º¯°æ µîÀÌ ¹ß»ýÇÑ °æ¿ìÀÓ. // - µû¶ó¼­ ÇØ´ç Content ¿¡ ´ëÇØ¼­´Â Retry ÇÏÁö ¾Ê°í.. Report ·Î±×¿¡¸¸ ±â·ÏÇÏ°í ³¡³½´Ù. void CReplicateThread::DoErrorProcess( string& szErrorMessage ) { // 2017-11-15 CHG huibong ´ë·® report ·Î±× ¹ß»ý °ü·Ã Ç׸ñ Á¶Á¤ (#31526) // - ÅäÅäµð½ºÅ© ¼­ºñ½º¿¡¼­ ¾÷·Îµå¿¡ µû¸¥ size mismatch ´ë·® report ·Î±× °ü·Ã // - error message °¡ "source file size not match" ÀÎ °æ¿ì report ·Î±×¿¡ ±â·ÏµÇÁö ¾Êµµ·Ï ¼öÁ¤ÇÑ´Ù. // - ½ÇÁ¦ error message ³»¿ëÀº "source file size not match.[ request: 877314616, local: 1137364384 ]" Çü½ÄÀ̹ǷΠ// - ¾ÕÀÇ ÀϺκи¸ ºñ±³ ó¸®. if(strncmp(szErrorMessage.c_str(), "source file size not match", 26) == 0 ) { return; } else { CReportLog reportLog; if( reportLog.Init( CServiceConfig::GetInstance()->GetLogPath() ) == false ) { std::string strErrorMessage; reportLog.GetLastError( strErrorMessage ); LOG( LERR, "report log init fail. [%s]", strErrorMessage.c_str() ); } else { reportLog.Write( "ERR", "[%s][Replication fail. check content[%s][%s][%llu][%s]]" , PROG_NAME , m_dataJob.m_OriginData.m_szOriginHostName.c_str() , m_dataJob.m_OriginData.m_szURI.c_str() , m_dataJob.m_OriginData.m_nContentLength , szErrorMessage.c_str() ); } return; } } // Replication 󸮿¡ ´ëÇØ FHS ¿¡¼­ ¼º°øÀ» ÀÀ´äÇÑ °æ¿ì ó¸®ÇÔ¼ö // - ¼º°øµÈ FHS ¿Í ½ÇÆÐµÈ FHS Á¤º¸¸¦ µ¿½Ã¿¡ Àü´ÞÇϹǷΠȮÀÎÇÏ¿© ó¸®ÇØ¾ß ÇÑ´Ù. void CReplicateThread::DoSuccessProcess() { // ¸â¹ö º¯¼ö¿¡ ÀúÀåµÈ Á¤º¸¸¦ ó¸®Çϱâ À§ÇÑ iterator std::map::iterator itSuccessFhs; // m_mapSuccessFhs ¿¡ ÀúÀåµÈ ¼º°ø °á°ú¿¡ ´ëÇÑ Ã³¸® // - success fhs host, hash_name ÀÇ Á¤º¸ ÀúÀåµÈ »óÅ // - Complete Queue ¿¡ ÀúÀå. for( itSuccessFhs = m_mapSuccessFhs.begin(); itSuccessFhs != m_mapSuccessFhs.end(); ++itSuccessFhs ) { // complete queue ¿¡ ÀúÀåÇϱâ À§ÇÑ °´Ã¼ Á¶¸³ CCompleteData completeResult; completeResult.m_OriginData = m_dataJob.m_OriginData; completeResult.m_szTargetHostName = itSuccessFhs->first; completeResult.m_szTargetFileNameHash = itSuccessFhs->second; // complete queue ¿¡ ÀúÀå ó¸® // - complete queue °¡ full »óÅÂÀÏ ¼ö ÀÖ¾î push ½ÇÆÐ °¡´É¼º Á¸Àç // - ÇÏÁö¸¸... complete queue ¿¡ ÀúÀå ¸øÇÒ °æ¿ì... // FHS ¿¡ »ý¼ºµÈ replication Àº óġ °ï¶õÇÑ ¾²·¹±â°¡ µÉ ¼ö ÀÖÀ¸¹Ç·Î.... // ÃÖ´ëÇÑ push ó¸®ÇÑ´Ù. while( m_pCompleteQueue->Push( completeResult ) == false ) { // push ½ÇÆÐ½Ã Àá½Ã ´ë±â ÈÄ Àç½Ãµµ sleep( 1 ); } // ¿øº» Data °´Ã¼¿¡ ¼º°øÇÑ FHS Á¤º¸ ÀԷ ó¸® // - ÀϺΠFHS ¿¡¸¸ º¹Á¦ ¼º°øÇϰí... ´Ù¸¥ FHS º¹Á¦´Â ½ÇÆÐÇÑ °æ¿ì... // - Retry ¸¦ ÅëÇØ º¹Á¦°¡ Àç½Ãµµ µÇµµ·Ï Çϱâ À§ÇÔ. m_dataJob.m_listSuccessHost.push_back( completeResult.m_szTargetHostName ); } // m_mapFailFhs ¿¡ ÀúÀåµÈ ½ÇÆÐ °á°ú¿¡ ´ëÇÑ Ã³¸® // - Àç½Ãµµ Ƚ¼ö Ãʰú½Ã Report ·Î±× ±â·Ï ÈÄ ¹ö¸² // - Àç½Ãµµ Ƚ¼ö ÀÌÇÏÀÎ °æ¿ì fail count Áõ°¡ ÈÄ Retry Queue ¿¡ ÀúÀå if( m_mapFailFhs.empty() == false ) { // ¸â¹ö º¯¼ö¿¡ ÀúÀåµÈ Á¤º¸¸¦ ó¸®Çϱâ À§ÇÑ iterator // - failed fhs host, error message std::map::iterator itFailFhs; // ½ÇÆÐ ³»¿ª¿¡ ´ëÇÑ ·Î±ë for( itFailFhs = m_mapFailFhs.begin(); itFailFhs != m_mapFailFhs.end(); ++itFailFhs ) { _LOG( LWAR, "CReplicateThread: replicate fail [%s]->[%s][%s]" , m_dataJob.m_OriginData.m_szURI.c_str() , itFailFhs->first.c_str() , itFailFhs->second.c_str() ); } // Àç½Ãµµ Ƚ¼ö È®ÀΠó¸® ¹× Retry queue °ü·Ã ó¸® DoFailProcess(); } return; }