/*************************************************************************** Source Data ----------------------------------------- begin : 2011/10/27 copyright : (C) 2011 SolutionBox Inc. author : Service 1 Team email : svc1@solbox.com version : 3.0.1 CopyRight(C) 2011 SolutionBox Inc. All Rights reserved. Redistribution and use in source and binary forms, with or with out modification, are not permitted in outside of SolutionBox Inc. ***************************************************************************/ #include "SourceData.h" #include "Database.h" #include "DataFile.h" #include "SyncList.h" #include "ServiceConfig.h" #include "RcdbInfo.h" #include "Util.h" #include "Logger.h" #include #include // Àüü ÀÚ·á·® ±¸ÇÏÁö ¸øÇßÀ» ¶§ ÇØ´ç °ª »ç¿ë #define MAX_LIMIT_OFFSET_COUNT 1000000 // Äõ¸®¹®¿¡ »ç¿ëÇÒ Àӽà ¹öÆÛ Size #define DEFAULT_BUFFER_SIZE 1024 CSourceData::CSourceData() : m_bDELETED_YN(false) , m_usedisplay(false) , m_ismaster(false) { } CSourceData::~CSourceData() { } bool CSourceData::Init(bool master, CSyncInfo sourceParam) { bool r = false; m_ismaster = master; m_sourceParam = sourceParam; if ( m_sourceParam.sync_type == SYNC_TYPE::NORMA_N_ONLY || m_sourceParam.sync_type == SYNC_TYPE::CHK_ONLY_N_ONLY ) m_bDELETED_YN = true; else m_bDELETED_YN = false; m_strErrorMessage.clear(); if (m_ismaster) r = m_dataFile.Init(m_sourceParam.file_master_name.c_str()); else r = m_dataFile.Init(m_sourceParam.file_slave_name.c_str()); if (r == false) { m_strErrorMessage = "Failed Create source file."; } return r; } bool CSourceData::Execute() { string errmsg; if (isError(errmsg) == true) { LOG(LERR, "Failed Initialization."); return false; } ostringstream msg; int nRet = ::pthread_create(&m_handleThread, NULL, CSourceData::Run, this); if(nRet != 0) { msg << "Thread create failed.: errno: " << errno; SetErrorMessage(msg.str()); LOG(LERR, msg.str().c_str()); return false; } return true; } void* CSourceData::Run(void* pVoid) { ostringstream msg; CSourceData* pSourceData = reinterpret_cast(pVoid); // pthread_detach( pthread_self() ); // È£ÃâÇÑ À§Ä¡¿¡¼­ pthread_joinÀ» »ç¿ëÇÑ´Ù. // 1. RCDB t_sms_sp_svc_product Á¤º¸¸¦ Á¶È¸ÇÏ¿© °¢ °í°´»çº° svcsync count Á¤º¸¸¦ °¡Á®¿Í ÀúÀåó¸®ÇÑ´Ù. // RCDB Á¢¼Ó 󸮸¦ À§ÇÑ °´Ã¼ »ý¼º DataBase* pPgSQL = new DataBase; if( pPgSQL == NULL ) { msg << "Cannot create DataBase object"; pSourceData->SetErrorMessage(msg.str()); LOG(LERR, msg.str().c_str()); return NULL; } CRcdbInfo info; info.Load(); // RCDB Á¢¼Ó ½Ãµµ ¹× Á¢¼Ó ½ÇÆÐ½Ã if (pPgSQL->PgOpenDB(info.m_strRcdbIp, info.m_nRcdbPort, info.m_strRcdbName, info.m_strRcdbAcct, info.m_strRcdbAcctPw) == NULL) { if (pPgSQL != NULL) { msg << "RCDB Connect failed [" << pPgSQL->GetErrorMessage() << "]"; pSourceData->SetErrorMessage(msg.str()); LOG(LERR, msg.str().c_str()); delete pPgSQL; pPgSQL = NULL; } return NULL; } // 2014.06.07 dadamin // ÀÛ¾÷ ´ë»ó Å×À̺í¸í °¡Á®¿À±â string tblname = pSourceData->GetTargetTable(pPgSQL); if ( tblname.size() <= 0 ) { if (pPgSQL != NULL) { string tranid = pSourceData->m_sourceParam.sync_slave; if (pSourceData->m_ismaster) tranid = pSourceData->m_sourceParam.sync_master; msg << "Failed to fetch Target table.[" << tranid << "]"; pSourceData->SetErrorMessage(msg.str()); LOG(LERR, msg.str().c_str()); delete pPgSQL; pPgSQL = NULL; } return NULL; } // 2014.08.06 dadamin // ÇØ´çÅ×À̺í Àüü ÀÚ·á·®¿¡ 10% °ªÀ» limit °ªÀ¸·Î »ç¿ëÇÑ´Ù. int64_t total = pSourceData->GetRows(pPgSQL, tblname.c_str()); int64_t getlimit = (total > 0 ? int64_t(total*0.1) : MAX_LIMIT_OFFSET_COUNT); getlimit = (getlimit == 0 ? MAX_LIMIT_OFFSET_COUNT : getlimit); int nResult = 0; // Query Resultset Clear. pPgSQL->PgClear(); /////////////////////////////////////////////////////////////////////////////////////////////////// int nNowResult = 0; string strResultUri, strResultType, strResultLength; string strResultLastDate, strResultDeletedYN, strResultFilenameHash; char* szResultUriTmp1 = NULL; char* szResultHasNameTmp1 = NULL; // SlaveÀÇ °æ¿ì ÆÄÀÏÀÌ ¾ø´Â °æ¿ì°¡ ¹ß»ýÇÒ ¼ö ÀÖÀ¸¹Ç·Î ¹Ì¸® ºóÆÄÀÏÀ» »ý¼ºÇØ µÐ´Ù. pSourceData->m_dataFile.Write(""); do { ostringstream sql; pPgSQL->PgClear(); // 2014.06.13 dadamin // ½Å±Ô Çü»ó(9.3) °æ¿ì display_name »ç¿ëÇÏ¿© ´ë¼Ò¹®ÀÚ ±â´ÉÀ» Áö¿øÇϸç, // ±âÁ¸ Çü»óÀÇ uri¿Í µ¿ÀÏÇÑ °ªÀ» °¡Áö°í ÀÖÀ¸¹Ç·Î ÇØ´ç Çü»óÀÎ °æ¿ì // uri ´ë½Å display_nameÀ¸·Î ¼Ò½º µ¥ÀÌÅ͸¦ °¡Á®¿À°Ô ÇÑ´Ù. if(pSourceData->m_usedisplay) sql << "SELECT display_name, resource_type, get_content_length, file_lastmodified, deleted_yn, filename_hash "; else sql << "SELECT uri, resource_type, get_content_length, file_lastmodified, deleted_yn, filename_hash "; sql << "FROM " << tblname << " "; sql << "WHERE get_lastmodified >= $1 AND get_lastmodified < $2 "; sql << "AND depth >= 0 AND depth <= 1000 "; sql << "AND uri LIKE '/' || $3 || '/%' "; if( pSourceData->m_bDELETED_YN ) sql << "AND deleted_yn = 'N' "; sql << "AND is_cache = 'N' "; if(pSourceData->m_usedisplay) sql << "ORDER BY display_name, get_lastmodified "; else sql << "ORDER BY uri, get_lastmodified "; sql << "LIMIT $4 OFFSET $5 "; #ifdef _DEBUG if(nNowResult == 0) cout << szQuery << endl; #endif // _DEBUG // //MAX_LIMIT_OFFSET_COUNT //nNowResult const char *paramValues[5]; ostringstream tmp; string strTime1, strTime2; string strLimit, strOffSet; tmp << str2longtime(pSourceData->m_sourceParam.start_time); strTime1 = tmp.str(); tmp.str(""); tmp << str2longtime(pSourceData->m_sourceParam.end_time); strTime2 = tmp.str(); tmp.str(""); tmp << getlimit; strLimit = tmp.str(); tmp.str(""); tmp << nNowResult; strOffSet = tmp.str(); tmp.str(""); paramValues[0] = strTime1.c_str(); paramValues[1] = strTime2.c_str(); if (pSourceData->m_ismaster) paramValues[2] = pSourceData->m_sourceParam.sync_master.c_str(); else paramValues[2] = pSourceData->m_sourceParam.sync_slave.c_str(); paramValues[3] = strLimit.c_str(); paramValues[4] = strOffSet.c_str(); nNowResult += getlimit; // Query ½ÇÇà //pPgSQL->PgDoExec(szQuery); pPgSQL->PgDoExecParams((char*) sql.str().c_str(), 5, paramValues); // Query °á°ú¸¦ °¡Á®¿Â´Ù. nResult = pPgSQL->PgResult(DataBase::NOT_CLEAR); if(nResult < 0) { pPgSQL->PgClear(); // RCDB t_dav_resource Å×À̺í Á¶È¸ ½ÇÆÐ msg << "RCDB Meta row get failed.[" << nResult << "][" << pPgSQL->GetErrorMessage() << "]"; pSourceData->SetErrorMessage(msg.str()); LOG(LERR, msg.str().c_str()); break; } // °á°ú Row ¼ö È®ÀÎ nResult = pPgSQL->GetNoTuples(); // Á¶È¸ °á°ú°¡ Á¸ÀçÇÏ´Â °æ¿ì Á¶È¸µÈ °á°ú¸¦ ÆÄÀÏ¿¡ ÀúÀå for (int n = 0; n < nResult; n++) { szResultUriTmp1 = NULL; szResultUriTmp1 = strchr(pPgSQL->GetValue(n, 0)+1, '/'); // URI (¾ÕÀÇ tran_id¸¦ »èÁ¦ÇÑ´Ù.) // skip Ű¿öµå Æ÷ÇԵǾî ÀÖ´Â °Ë»çÇÑ´Ù. if(pSourceData->IsSkipKeyword(szResultUriTmp1) == true) { msg << "SKIP Source data." << szResultUriTmp1; _LOG(LNOT, "%s", msg.str().c_str()); msg.str(""); //REPORT_SUCCESS("[%s] [SKIP] %s (source data has skip keyword.)", // pSourceData->m_sourceParam.m_tranid.c_str(), szResultUriTmp1); continue; } strResultUri = szResultUriTmp1; strResultType = pPgSQL->GetValue(n, 1); // resource_type strResultLength = pPgSQL->GetValue(n, 2); // get_content_length strResultLastDate = pPgSQL->GetValue(n, 3); // file_lastmodified strResultDeletedYN = pPgSQL->GetValue(n, 4); // deleted_yn // µð·ºÅ丮 °æ¿ì hash°¡ ¾ø´Â °æ¿ìµµ ÀÖÀ¸¹Ç·Î ÆÄÀϸ¸ hash »ç¿ë szResultHasNameTmp1 = NULL; if ( strResultType.compare("0") == 0 ) szResultHasNameTmp1 = strrchr(pPgSQL->GetValue(n, 5) + 1, '/'); // filename_hash ( º¼·ý Á¤º¸ »èÁ¦ÇÔ) if (szResultHasNameTmp1) strResultFilenameHash = szResultHasNameTmp1; else strResultFilenameHash = ""; if(strResultUri.size() <= 0) // URI°¡ ¾ø´Â °æ¿ì ÀúÀå ¾ÈÇÔ continue; if(strResultType.size() <= 0) // ÆÄÀÏ Å¸ÀÔ°ªÀÌ NULL ÀÏ °æ¿ì 0À¸·Î ±âº» ¼ÂÆÃ strResultType = "0"; if (strResultLastDate.size() <= 0) // ÆÄÀÏ Å©±â°ªÀÌ NULL ÀÏ °æ¿ì 0À¸·Î ±âº» ¼ÂÆÃ strResultLastDate = "0"; // ÇØ´ç Á¤º¸¸¦ ãÀº °æ¿ì pSourceData->m_dataFile.Write("%s|%s|%s|%s|%s|%s", strResultUri.c_str(), strResultFilenameHash.c_str(), strResultType.c_str(), strResultLength.c_str(), strResultLastDate.c_str(), strResultDeletedYN.c_str()); } #ifdef _DEBUG cout << "Generate tmp file : " << pSourceData->m_dataFile.GetFilePath() << "," << pSourceData->m_dataFile.GetFileName() << ", run count=" << nResult << " / " << nNowResult - MAX_LIMIT_OFFSET_COUNT << endl; #endif // _DEBUG } while (getlimit == nResult); // do while() ////////////////////////////////////////////////////////////////////////////////////////////////// // DB Object »èÁ¦ ó¸®. if( pPgSQL != NULL ) { pPgSQL->PgClear(); pPgSQL->PgCloseDB(); delete pPgSQL; pPgSQL = NULL; } return NULL; } bool CSourceData::IsSkipKeyword(string key) { bool r = false; vector skipwords = CServiceConfig::GetInstance()->GetSkipWord(); int keycnt = skipwords.size(); for( int i=0; i< keycnt; ++i ) { string k = skipwords[i]; vector v; StringSplit(k, "|", v); string::size_type pos; pos = key.find(v[1]); if ( pos != string::npos ) { switch (v[0][0]) { case 'h': if (pos == 0) { if (v[1] == key || key.at(v[1].size()) == '/') r = true; } break; case 'm': if(pos > 0 && key.size() > pos + v[1].size()) r = true; break; case 't': if(pos > 0 && key.size() == pos + v[1].size()) r = true; break; default: break; } } } return r; } // 2014.06.07 dadamin // ÀÛ¾÷ ´ë»ó Å×À̺í string CSourceData::GetTargetTable(DataBase *d) { string r; ostringstream msg; if (d == NULL) return ""; string sql = "SELECT * FROM pg_tables WHERE schemaname = 'public' AND tablename = 't_dav_resource'"; d->PgDoExec(sql); if (d->PgResult(DataBase::NOT_CLEAR) < 0) { d->PgClear(); msg << "SetTargetTableType failed : " << d->GetErrorMessage(); LOG(LERR, msg.str().c_str()); return ""; } if (d->GetNoTuples() > 0) { m_usedisplay = false; r = "t_dav_resource"; } else { m_usedisplay = true; if (m_ismaster) r = "t_meta_" + m_sourceParam.sync_master; else r = "t_meta_" + m_sourceParam.sync_slave; } d->PgClear(); msg << "Set Target Table : " << r; LOG(LDBG, msg.str().c_str()); return r; } static int64_t convert(string &s) { if(s.size() == 0 ) return 0; int64_t v = 0; size_t i=0; char sign = (s[0] == '-' || s[0] == '+') ? (++i, s[0]) : '+'; for( ; i < s.size(); ++i) { if ( s[i] < '0' || s[i] > '9' ) return 0; v = v * 10 + s[i] - '0'; } return sign == '-' ? -v : v; } // ÇØ´ç Å×À̺í Àüü rows int64_t CSourceData::GetRows(DataBase *d, const char* tblname) { int64_t r = 0; ostringstream msg; // SELECT relname, reltuples from pg_class where relname ='t_meta_346'; if (d == NULL) return 0; ostringstream sql; sql << "SELECT relname, reltuples::bigint from pg_class where relname = "; sql << "'" << tblname << "'"; d->PgDoExec((char*)sql.str().c_str()); if (d->PgResult(DataBase::NOT_CLEAR) < 0) { d->PgClear(); msg << "Get Table Rows failed : " << d->GetErrorMessage(); LOG(LERR, msg.str().c_str()); return 0; } if (d->GetNoTuples() > 0) { string t = d->GetValue(0, 1); r = convert(t); } msg << "Table : " << tblname << ", Rows : "<< r; LOG(LDBG, msg.str().c_str()); d->PgClear(); return r; }