/*************************************************************************** Work Pool ----------------------------------------- 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 "WorkPool.h" #include "Validation.h" #include "Logger.h" #include "Util.h" #include #include #include #define DIFF_SPLIT_CNT 6 // diff file format split count #define SLEEP_TIME 1000 //microsecond #define _LOGMSG(level, msg) \ _LOG(level, "%s", msg.str().c_str());\ msg.str(""); CWorkPool *CWorkPool::m_inst = NULL; // work CWork::CWork() : m_step(-5), m_exit(false), m_enablesync("0000") { m_nofi = NULL; pthread_mutex_init(&m_workmutex, NULL); pthread_cond_init(&m_workcond, NULL); } CWork::~CWork() { pthread_mutex_destroy(&m_workmutex); pthread_cond_destroy(&m_workcond); } void* CWork::working(void * pdata) { ostringstream msg; CWork* pObject = reinterpret_cast(pdata); //pthread_detach( pthread_self() ); #ifdef _DEBUG cout << "work::working start - " << pthread_self() << endl; #endif // _DEBUG while(pObject->m_exit == false) { pthread_mutex_lock(&pObject->m_workmutex); pObject->m_step = -1; int err = pthread_cond_wait(&pObject->m_workcond, &pObject->m_workmutex); pObject->m_step = 0; #ifdef _DEBUG cerr << "work::working - signal : " << pthread_self() << "," << pObject->m_exit << endl; #endif // _DEBUG if ( err == 0 && pObject->m_exit == false) { pObject->m_step = 1; short success = 0; msg << "Valid Start : " << pObject->m_rundata; _LOGMSG(LDBG, msg); do { // add uri pObject->m_step = 2; if (CWorkPool::getInstance()->addworkuri(pObject->m_syncinfo.sync_master, pObject->m_rundata, pObject->m_workuri, true) == false) { LOG(LERR, "Failed work uri map add [%s].", pObject->m_rundata.c_str()); success = -1; break; } // validation pObject->m_step = 3; CValidation v(pObject->m_syncinfo, pObject->m_rundata); if (v.CheckValidation() == false) success = -2; pObject->m_step = 4; } while (false); if(pObject->m_nofi) { pObject->m_step = 6; #ifdef _DEBUG cerr << "Work Thread Notify Call."<< endl; #endif //_DEBUG pObject->m_nofi(pObject->m_parm, success); } pObject->m_step = 7; msg << "Valid End : " << pObject->m_rundata; _LOGMSG(LDBG, msg); if(pObject->m_workuri.size()) { CWorkPool::getInstance()->delworkuri(pObject->m_workuri); } CWorkPool::getInstance()->ReleaseWork(pObject); } else { pObject->m_step = -3; if(pObject->m_exit == false) { pObject->m_step = -4; msg << "Work Thread Error."; //LOGACERR(LCRT, msg); LOG(LCRT, msg.str().c_str()); } else { pObject->m_step = -5; /* nothing -- signal exit */ } } pObject->m_step = -6; pthread_mutex_unlock(&pObject->m_workmutex); } #ifdef _DEBUG cerr << "work::working end - " << pthread_self() << endl; #endif // _DEBUG return NULL; } bool CWork::init() { int nRet = pthread_create(&m_thread, 0, CWork::working, this); if( nRet ) { cerr << "Thread create failed.: errno: " << errno << endl; return false; } sleep(0); return true; } void CWork::setexit(bool v) { m_exit = v; pthread_mutex_lock(&m_workmutex); pthread_cond_signal(&m_workcond); pthread_mutex_unlock(&m_workmutex); } bool CWork::run(CSyncInfo info, string rundata, work_notifyfn nofi /* = NULL */, void * parm /* = NULL */) { m_syncinfo = info; m_rundata = rundata; m_parm = parm; m_nofi = nofi; ostringstream msg; //msg << "Work Run : TranID(" <" << m_slave.m_tranid << // "), UserSeq(" << m_master.m_userseq << "=>" << m_slave.m_userseq << ")" << // ", Sync Data - " << m_rundata; //_LOGACOUT(LDBG, msg); //spin lock int64_t looptime = 0; do { solusleep(SLEEP_TIME); looptime += SLEEP_TIME; if( looptime > (10 *1000*1000) ) { msg << "Work Loop.... 10 sec over :" << m_rundata; LOG(LNOT, "%s", msg.str().c_str()); break; } } while (m_step != -1); pthread_cond_signal(&m_workcond); return true; } // work pool CWorkPool::CWorkPool() { pthread_mutex_init(&m_mutex, NULL); pthread_mutex_init(&m_mutexuri, NULL); pthread_mutex_init(&m_mutextry, NULL); } CWorkPool::~CWorkPool() { pthread_mutex_destroy(&m_mutex); pthread_mutex_destroy(&m_mutexuri); pthread_mutex_destroy(&m_mutextry); } CWorkPool* CWorkPool::getInstance() { if(CWorkPool::m_inst == NULL) { CWorkPool::m_inst = new CWorkPool(); } return CWorkPool::m_inst; } void CWorkPool::release() { if( CWorkPool::m_inst != NULL) { m_inst->DestroyPool(); delete CWorkPool::m_inst; CWorkPool::m_inst = NULL; } } int CWorkPool::CreatePool( int poolcnt /* = 10 */ ) { // pool for(int i=0 ; i < poolcnt ; i++) { srand ( time(NULL) ); CWork * w = new CWork(); if( w->init() == false) { delete w; break; } //m_pool.insert(make_pair(w, CWorkPool::NOTWORK)); m_pool.insert(pair(w, CWorkPool::NOTWORK)); } if( m_pool.size() < static_cast(poolcnt) ) { DestroyPool(); return -1; } return 0; } int CWorkPool::DestroyPool() { map::iterator iter; while(m_pool.size() > 0 ) //for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ ) { iter = m_pool.begin(); if(iter->second == CWorkPool::NOTWORK) { CWork *data = static_cast(iter->first); data->setexit(true); pthread_join(*data->getworkhandle(), NULL); m_pool.erase(iter); delete (CWork *)data; } //sleep(1); } //m_pool.clear(); return m_pool.size(); } CWork* CWorkPool::GetWorkPool(int timeout) { CWork * r = NULL; int64_t usetime = 0; int64_t out = timeout * 1000 * 1000; do { pthread_mutex_lock(&m_mutex); map::iterator iter; for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ ) { if(iter->second == CWorkPool::NOTWORK) { iter->second = CWorkPool::WORKING; r = iter->first; break; } } if( r == NULL ) { solusleep(SLEEP_TIME); if( out > 0 ) { usetime += SLEEP_TIME; if( usetime > out) { ostringstream msg; msg << "Get Work Pool Timeout."; //LOGACERR(LERR, msg); LOG(LERR, msg.str().c_str()); pthread_mutex_unlock(&m_mutex); break; } } } pthread_mutex_unlock(&m_mutex); } while (r == NULL); return r; } void CWorkPool::ReleaseWork(CWork *w) { //pthread_mutex_lock(&m_mutex); map::iterator iter = m_pool.find(w); if( iter != m_pool.end() ) { if(iter->second==CWorkPool::WORKING) iter->second=CWorkPool::NOTWORK; } else { ostringstream msg; msg << "unknown work pool."; //LOGACERR(LWAR, msg); LOG(LWAR, msg.str().c_str()); } //pthread_mutex_unlock(&m_mutex); } void CWorkPool::printstatus(string prefixed) { int w = 0, n = 0; map::iterator iter; for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ ) { if(iter->second == CWorkPool::NOTWORK) { ++n; } else { ++w; } } ostringstream msg; if( prefixed.empty() == false ) msg << "[" << prefixed << "]"; msg << "Work Pool - " <<"total : " << m_pool.size() << "(" << w << "/" << n << ")"; //_LOGACOUT(LINF, msg); _LOG(LINF, msg.str().c_str()); } void CWorkPool::printstatusex(string prefixed) { ostringstream msg; map::iterator iter; for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ ) { if(iter->second == CWorkPool::NOTWORK) { msg << "Work Pool(NOTWORK) - " << iter->first->getrundata() << "," << iter->first->getsetp(); } else { msg << "Work Pool(WORKING) - " << iter->first->getrundata() << "," << iter->first->getsetp(); } if( prefixed.empty() == false ) msg << "[" << prefixed << "]"; //_LOGACOUT(LINF, msg); _LOG(LINF, "%s", msg.str().c_str()); } } bool CWorkPool::addworkuri(string tranid, string uri, string &workuri, bool sourcedata, int timeout) { bool r = true; string key; ostringstream msg; if(sourcedata) { vector strSplit; StringSplit(uri, "|", strSplit, true); if(strSplit.size() != DIFF_SPLIT_CNT) { pthread_mutex_unlock(&m_mutexuri); msg << "addworkuri sync file string split caution : [" << uri << "]"; //LOGACERR(LERR, msg); LOG(LERR, "%s", msg.str().c_str()); return false; } key = "/" + tranid + strSplit[0] + "|[Size=" + strSplit[2] + "]"; } else key = "/"+ tranid + uri; int64_t out = 0, usetime = 0; out = timeout * 1000 * 1000; TRY_ADD_WORK_URI: pthread_mutex_lock(&m_mutexuri); workurimap::iterator find = m_workurimap.find(key); if (find != m_workurimap.end()) { pthread_mutex_unlock(&m_mutexuri); msg << "Work uri duplication occurred and to add work uri try again." << key; _LOGMSG(LDBG, msg); // try solusleep(SLEEP_TIME); usetime += SLEEP_TIME; if(timeout > 0 && usetime > out) { r = false; msg << "Work adduri Timeout." << key; //LOGACERR(LERR, msg); LOG(LERR, "%s", msg.str().c_str()); pthread_mutex_unlock(&m_mutexuri); return false; } goto TRY_ADD_WORK_URI; } else { // add workuri = key; m_workurimap[key] = 1; //pthread_mutex_unlock(&m_mutexuri); } pthread_mutex_unlock(&m_mutexuri); return r; } bool CWorkPool::delworkuri(string key) { pthread_mutex_lock(&m_mutexuri); // deleted m_workurimap.erase(key); pthread_mutex_unlock(&m_mutexuri); return true; }