base
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
#include "ClientThread.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "RcSyncdRequestData.h"
|
||||
#include "ModeMaster.h"
|
||||
#include "ModeSlave.h"
|
||||
#include "ModeSync.h"
|
||||
|
||||
|
||||
// 생성자
|
||||
CClientThread::CClientThread( CProcessStatus * pStatus, int clientSocket, char * pszClientAddress )
|
||||
: m_pProcessStatus( pStatus )
|
||||
, m_socketClientDesc( clientSocket )
|
||||
, m_client( clientSocket )
|
||||
, m_strClientIp( pszClientAddress )
|
||||
{
|
||||
// 멤버 변수 초기화
|
||||
m_threadHandle = 0;
|
||||
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CClientThread:: ~CClientThread()
|
||||
{
|
||||
// Thread 동작 정지 처리
|
||||
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로 업무 Flow 수정시 주의할 것
|
||||
if( m_threadHandle != 0 )
|
||||
pthread_cancel( m_threadHandle );
|
||||
|
||||
// client 와 연결된 socket 종료 처리
|
||||
m_client.Close();
|
||||
|
||||
}
|
||||
|
||||
// thread 를 생성하여 처리 업무 flow start
|
||||
bool CClientThread::Start()
|
||||
{
|
||||
int nRet = ::pthread_create( &m_threadHandle, NULL, CClientThread::threadFunc, this );
|
||||
if( nRet != 0 )
|
||||
{
|
||||
// Thread 생성 실패시
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// 스레드 함수
|
||||
void* CClientThread::threadFunc( void* arg )
|
||||
{
|
||||
CClientThread* pObject = reinterpret_cast<CClientThread *>( arg );
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
// Client Thread Count 1 증가 처리
|
||||
pObject->m_pProcessStatus->PlusClientCount();
|
||||
|
||||
// 실제 작업 수행.
|
||||
pObject->Execute();
|
||||
|
||||
// Client Thread Count 1 감소 처리
|
||||
pObject->m_pProcessStatus->MinusClientCount();
|
||||
|
||||
// Thread 종료시 m_threadHandle 값을 초기화 처리.
|
||||
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
|
||||
// 객체 자동 delete 처리.
|
||||
delete pObject;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// client request 요청을 수신하여 이에 따른 job 을 수행
|
||||
void CClientThread::Execute()
|
||||
{
|
||||
_LOG( LINF, "client thread start [%s]", m_strClientIp.c_str() );
|
||||
|
||||
// Packet Header 정보를 이용한 client 요청 분석
|
||||
int nRead;
|
||||
bool bRequest;
|
||||
bool bFromClient;
|
||||
char command;
|
||||
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
// socket 연결을 아래 job 등에서 일부로 끊은 경우를 처리하기 위한 코드.
|
||||
// - Server socket 이지만.. 통신 관련 오류시.. server 가 socket 을 끊을 수 있다.
|
||||
// - 이는 file 전송 등으로 인해 불필요한 data 가 통신상에 남아 있을 수 있기 때문임.
|
||||
if( m_client.IsValidSocket() == false )
|
||||
break;
|
||||
|
||||
// Header 수신
|
||||
nRead = m_client.GetHeaderInfo( bRequest, bFromClient, command );
|
||||
|
||||
if( nRead == 0 )
|
||||
{
|
||||
// timeout 발생시 - 잠시 대기 후 계속 수신 대기
|
||||
sleep( 2 );
|
||||
continue;
|
||||
}
|
||||
else if( nRead < 0 )
|
||||
{
|
||||
// Socket 접속 종료 또는 오류 발생시
|
||||
// - 관련 로그는 해당 모듈에서 다 찍었으므로.. 여기서는 루프 종료 처리.
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// data 수신시.
|
||||
// 정의된 packet 에만 동작.. 그외에는 무시.
|
||||
if( bRequest == true && bFromClient == true )
|
||||
{
|
||||
// 외부 tool (cmove) 또는 scheduler 에서 보낸 요청인 경우.
|
||||
switch( command )
|
||||
{
|
||||
case CLIENT_COMMAND_SYNC: // Client 에서 동기화 수행 요청 수신시
|
||||
_LOG( LINF, "client[%s] request sync.", m_strClientIp.c_str() );
|
||||
ClientRequestSync();
|
||||
break;
|
||||
|
||||
default: // 미정의 Type 수신시.. client 와 연결 해제 처리
|
||||
LOG( LERR, "client[%s] request unknown. check request[%02x]", m_strClientIp.c_str(), command );
|
||||
m_client.PrintHeaderToLog();
|
||||
m_client.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( bRequest == true && bFromClient == false )
|
||||
{
|
||||
// Master rc_syncd 에서 보낸 요청인 경우.
|
||||
switch( command )
|
||||
{
|
||||
case PROCESS_CONTENT_LIST: // Master 로 부터 Content 정보 목록 요청 수신시
|
||||
_LOG( LINF, "master[%s] request content list.", m_strClientIp.c_str() );
|
||||
ProcessContentList();
|
||||
break;
|
||||
|
||||
case PROCESS_CONTENT_SYNC: // Master 로 부터 동기화 수행 작업 요청 수신시.
|
||||
_LOG( LINF, "master[%s] request sync job.", m_strClientIp.c_str() );
|
||||
ProcessContentSync();
|
||||
break;
|
||||
|
||||
default: // 미정의 Type 수신시.. 연결 해제 처리
|
||||
LOG( LERR, "master[%s] request unknown. check request[%02x]", m_strClientIp.c_str(), command );
|
||||
m_client.PrintHeaderToLog();
|
||||
m_client.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 그 외.. 정의 되지 않은 요청인 경우. => 연결 해제 처리.
|
||||
LOG( LERR, "Not defined packet header. client[%s]", m_strClientIp.c_str() );
|
||||
m_client.PrintHeaderToLog();
|
||||
m_client.Close();
|
||||
}
|
||||
}
|
||||
|
||||
} // while (1)
|
||||
|
||||
|
||||
// client 와 연결 종료 처리.
|
||||
_LOG( LINF, "client connection closed.[%s]", m_strClientIp.c_str() );
|
||||
m_client.Close();
|
||||
}
|
||||
|
||||
// Client로 부터 Sync 요청 수신시 이를 처리하기 위한 함수.
|
||||
void CClientThread::ClientRequestSync()
|
||||
{
|
||||
m_pProcessStatus->PlusMasterModeCount();
|
||||
|
||||
// 수신된 Data 를 저장할 객체 생성
|
||||
CReqMasterData requestData;
|
||||
if( m_client.RecvBodySyncFromClient( requestData ) == false )
|
||||
{
|
||||
// Data 수신 실패시
|
||||
LOG( LERR, "client[%s] request sync. data receive fail.", m_strClientIp.c_str() );
|
||||
m_client.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Request Data 수신 성공시.
|
||||
LOG( LDBG, "client[%s] request sync. type[%d] time[%s]~[%s] svc[%s]"
|
||||
, m_strClientIp.c_str()
|
||||
, requestData.sync_type, requestData.start_time.c_str(), requestData.end_time.c_str()
|
||||
, ( requestData.one_service.empty() == true ? "ALL" : requestData.one_service.c_str())
|
||||
);
|
||||
|
||||
// Master Mode 처리를 위한 객체 생성
|
||||
CMasterMode modeMaster( &m_client );
|
||||
if( modeMaster.CreateSyncList( requestData ) == true )
|
||||
{
|
||||
// 초기화 작업이 정상적으로 완료된 경우...
|
||||
// 업무 Flow 수행함수 실행.
|
||||
modeMaster.Execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 초기화 작업 실패시
|
||||
std::string strErrorMessage = "sync list initialize fail.";
|
||||
if( m_client.SendResultSyncToClient( false, strErrorMessage ) == false )
|
||||
{
|
||||
LOG( LERR, "client[%s] sync result[error] send fail.", m_strClientIp.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pProcessStatus->MinusMasterModeCount();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Content 목록 정보 요청 ( Slave Mode ) 인 경우 이를 처리하기 위한 함수.
|
||||
void CClientThread::ProcessContentList()
|
||||
{
|
||||
m_pProcessStatus->PlusSlaveModeCount();
|
||||
|
||||
// 수신된 Data 를 저장할 객체 생성
|
||||
CReqSlaveData requestData;
|
||||
if( m_client.RecvBodyContentListFromMaster( requestData ) == false )
|
||||
{
|
||||
// Data 수신 실패시
|
||||
LOG( LERR, "master[%s] request content_list. but data receive fail.", m_strClientIp.c_str() );
|
||||
m_client.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Request Data 수신 성공시.
|
||||
LOG( LDBG, "master[%s] request content list. type[%d] time[%s]~[%s] master[%s] slave[%s]"
|
||||
, m_strClientIp.c_str()
|
||||
, requestData.sync_type, requestData.start_time.c_str(), requestData.end_time.c_str()
|
||||
, requestData.master.c_str(), requestData.slave.c_str()
|
||||
);
|
||||
|
||||
// Slave Mode 처리를 위한 객체 생성
|
||||
CSlaveMode modeSlave( &m_client );
|
||||
if( modeSlave.CreateSyncList( requestData ) == true )
|
||||
{
|
||||
// 초기화 작업이 정상적으로 완료된 경우...
|
||||
// 업무 Flow 수행함수 실행.
|
||||
modeSlave.Execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 초기화 작업 실패시
|
||||
std::string strErrorMessage = "sync list initialize fail.";
|
||||
if( m_client.SendErrorContentListToMaster( strErrorMessage ) == false )
|
||||
{
|
||||
LOG( LERR, "master[%s] content_list result[error] send fail.", m_strClientIp.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pProcessStatus->MinusSlaveModeCount();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Content 동기화 요청 ( Sync Mode ) 인 경우 이를 처리하기 위한 함수.
|
||||
void CClientThread::ProcessContentSync()
|
||||
{
|
||||
m_pProcessStatus->PlusSyncModeCount();
|
||||
|
||||
// 수신된 Data 를 저장할 객체 생성
|
||||
CReqSyncData requestData;
|
||||
|
||||
if( m_client.RecvBodyExecuteSyncFromMaster( requestData ) == false )
|
||||
{
|
||||
// Data 수신 실패시
|
||||
LOG( LERR, "master[%s] request execute sync. but data receive fail.", m_strClientIp.c_str() );
|
||||
m_client.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Request Data 수신 성공시.
|
||||
LOG( LDBG, "master[%s] request execute sync. type[%d] time[%s]~[%s] master[%s] slave[%s]"
|
||||
, m_strClientIp.c_str()
|
||||
, requestData.sync_type, requestData.start_time.c_str(), requestData.end_time.c_str()
|
||||
, requestData.master.c_str(), requestData.slave.c_str()
|
||||
);
|
||||
|
||||
// Sync Mode 처리를 위한 객체 생성
|
||||
CSyncMode modeSync( &m_client );
|
||||
if( modeSync.CreateSyncList( requestData ) == true )
|
||||
{
|
||||
// modeSync 객체 초기화 성공시...
|
||||
// socket 에서 sync 파일 정보를 수신받아 저장처리한다.
|
||||
// 하지만.. 파일명 정보가 CSyncMode 내부에 저장되어 있으므로...
|
||||
// 이에 대한 수신 처리 및 응답 처리는 CSyncMode 내의 Execute 함수 내에서 처리한다.
|
||||
|
||||
// 초기화 작업이 정상적으로 완료된 경우...
|
||||
// 업무 Flow 수행함수 실행.
|
||||
modeSync.Execute();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 초기화 작업 실패시
|
||||
std::string strErrorMessage = "sync list initialize fail.";
|
||||
if( m_client.SendResultExecuteSyncToMaster( false, strErrorMessage ) == false )
|
||||
{
|
||||
LOG( LERR, "master[%s] execute sync result[error] send fail.", m_strClientIp.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_pProcessStatus->MinusSyncModeCount();
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/***************************************************************************
|
||||
접속 요청 Client 에 대한 처리를 담당하는 Thread class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/12
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : storage dev team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __CLIENT_THREAD_H__
|
||||
#define __CLIENT_THREAD_H__
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
|
||||
#include "ProcessStatus.h"
|
||||
#include "ProcessSocketControl.h"
|
||||
|
||||
|
||||
// CClientThread
|
||||
// rc_syncd 에서 accept 처리한 각 client 세션을 처리하기 위한 Thread class
|
||||
class CClientThread
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
CClientThread( CProcessStatus * pStatus, int clientSocket, char * pszClientAddress );
|
||||
|
||||
// 소멸자
|
||||
~CClientThread();
|
||||
|
||||
// thread 를 생성하여 처리 업무 flow start
|
||||
bool Start();
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 스레드 함수
|
||||
static void* threadFunc( void* arg );
|
||||
|
||||
// client request 요청을 수신하여 이에 따른 job 을 수행
|
||||
void Execute();
|
||||
|
||||
// Client로 부터 Sync 요청 수신시 이를 처리하기 위한 함수.
|
||||
void ClientRequestSync();
|
||||
|
||||
// Content 목록 정보 요청 ( Slave Mode ) 인 경우 이를 처리하기 위한 함수.
|
||||
void ProcessContentList();
|
||||
|
||||
// Content 동기화 요청 ( Sync Mode ) 인 경우 이를 처리하기 위한 함수.
|
||||
void ProcessContentSync();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
// 프로세스 상태를 관리하는 CProcessStatus 객체에 대한 포인터
|
||||
// - 생성자를 통해 전달받음
|
||||
CProcessStatus * m_pProcessStatus;
|
||||
|
||||
// Client Socket discriptor
|
||||
// - 생성자를 통해 전달받음.
|
||||
int m_socketClientDesc;
|
||||
|
||||
// client 와 통신 관련 처리를 수행하기 위한 control 객체
|
||||
CProcessSocketControl m_client;
|
||||
|
||||
// Client IP Address
|
||||
// - 생성자를 통해 전달받음
|
||||
std::string m_strClientIp;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* __CLIENT_THREAD_H__ */
|
||||
|
||||
@@ -0,0 +1,545 @@
|
||||
/***************************************************************************
|
||||
Database Connection Pool
|
||||
-----------------------------------------
|
||||
begin : 2012/05/13
|
||||
copyright : (C) 2011 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.1.0
|
||||
|
||||
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 "DBConnPool.h"
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#define GET_SLEEP 1000 // microsecond
|
||||
|
||||
CMasterDBPool *CMasterDBPool::m_inst = NULL;
|
||||
CSlaveDBPool *CSlaveDBPool::m_inst = NULL;
|
||||
|
||||
CDBConnPool::CDBConnPool(CDataBaseInfo info)
|
||||
: m_dbinfo(info), m_exitpool(false), m_lastset(NULL), m_alivetime(-1), m_tabletype(-1)
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_mutex_init(&m_alivemutex, NULL);
|
||||
pthread_cond_init(&m_alivecond, NULL);
|
||||
}
|
||||
|
||||
CDBConnPool::~CDBConnPool()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_mutex_destroy(&m_alivemutex);
|
||||
pthread_cond_destroy(&m_alivecond);
|
||||
}
|
||||
|
||||
int CDBConnPool::ReCreatePool(int poolcnt /* = 4 */)
|
||||
{
|
||||
// pool
|
||||
for (int i = 0; i < poolcnt; i++)
|
||||
{
|
||||
DataBase * tmp = new DataBase();
|
||||
|
||||
if (tmp->PgOpenDB(m_dbinfo.m_hostaddr, m_dbinfo.m_port, m_dbinfo.m_dbname, m_dbinfo.m_user, m_dbinfo.m_pw) == NULL)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cerr << "Database connect error : " << tmp->GetErrorMessage() << endl;
|
||||
#endif // _DEBUG
|
||||
LOG(LERR, "Database connect error.[%s]", tmp->GetErrorMessage().c_str());
|
||||
delete tmp;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2014.06.06 dadamin
|
||||
// Pool 생성 시 현재 생성된 DB의 형상을 체크한다.
|
||||
if (m_tabletype < 0)
|
||||
{
|
||||
if (SetTargetTableType(tmp) == false)
|
||||
{
|
||||
delete tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_poolmap.insert(make_pair(tmp, CDBConnPool::POOL_FREE));
|
||||
}
|
||||
|
||||
LOG(LDBG, "DB Pool Recreated.[CNT=%zu]", m_poolmap.size());
|
||||
return m_poolmap.size();
|
||||
}
|
||||
|
||||
int CDBConnPool::CreatePool( int poolcnt /* = 4 */ )
|
||||
{
|
||||
// keep alive thread
|
||||
int nRet = pthread_create(&m_keepalive, 0, CDBConnPool::KeepPoolAlive, this);
|
||||
if( nRet )
|
||||
{
|
||||
cerr << "Thread create failed.: errno: " << errno << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// pool
|
||||
m_poolsize = ReCreatePool(poolcnt);
|
||||
|
||||
if( m_poolmap.size() == 0 )
|
||||
{
|
||||
// alive thread end
|
||||
m_exitpool = true;
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
pthread_join(m_keepalive, NULL);
|
||||
m_exitpool = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return m_poolsize;
|
||||
}
|
||||
|
||||
int CDBConnPool::DestroyPool()
|
||||
{
|
||||
m_exitpool = true;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
while(m_poolmap.size() > 0 )
|
||||
{
|
||||
iter = m_poolmap.begin();
|
||||
if(iter->second == CDBConnPool::POOL_FREE || iter->second == CDBConnPool::POOL_ERR)
|
||||
{
|
||||
DataBase *data = static_cast<DataBase *>(iter->first);
|
||||
delete (DataBase *) data;
|
||||
m_poolmap.erase(iter);
|
||||
}
|
||||
else
|
||||
sleep(1);
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
//
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
pthread_join(m_keepalive, NULL);
|
||||
|
||||
/*
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == CDBConnPool::POOL_FREE)
|
||||
{
|
||||
DataBase *data = static_cast<DataBase *>(iter->first);
|
||||
delete (DataBase *) data;
|
||||
m_poolmap.f
|
||||
m_poolmap.erase(iter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
m_poolsize = m_poolmap.size();
|
||||
return m_poolsize;
|
||||
}
|
||||
|
||||
DataBase * CDBConnPool::GetConnFromPool(int timeout)
|
||||
{
|
||||
ostringstream msg;
|
||||
DataBase * r = NULL;
|
||||
|
||||
int64_t usetime = 0;
|
||||
int64_t out = timeout*1000*1000;
|
||||
|
||||
time_t t = time(NULL);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.begin();
|
||||
if(m_lastset)
|
||||
{
|
||||
iter = m_poolmap.find(m_lastset);
|
||||
if( iter != m_poolmap.end() )
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
if( m_poolmap.empty() )
|
||||
{
|
||||
if (ReCreatePool(m_poolsize) == 0)
|
||||
{
|
||||
msg << "DB Pool empty.";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( iter == m_poolmap.end() )
|
||||
{
|
||||
iter = m_poolmap.begin();
|
||||
}
|
||||
|
||||
for( ; !m_poolmap.empty()&& iter != m_poolmap.end(); )
|
||||
{
|
||||
if(iter->second == CDBConnPool::POOL_FREE)
|
||||
{
|
||||
iter->second = CDBConnPool::POOL_USE;
|
||||
r = iter->first;
|
||||
m_lastset = r;
|
||||
break;
|
||||
}
|
||||
else if (iter->second == CDBConnPool::POOL_ERR)
|
||||
{
|
||||
DataBase * d = iter->first;
|
||||
m_poolmap.erase(iter++);
|
||||
if(d == m_lastset)
|
||||
m_lastset = NULL;
|
||||
delete d;
|
||||
}
|
||||
else
|
||||
iter++;
|
||||
}
|
||||
|
||||
if( r == NULL)
|
||||
{
|
||||
solusleep(GET_SLEEP);
|
||||
if( usetime > 10*1000*1000)
|
||||
{
|
||||
msg << "GetConnFromPool have waited longer than 10 seconds.";
|
||||
LOG(LDEV1, msg.str().c_str());
|
||||
}
|
||||
|
||||
if( out > 0 )
|
||||
{
|
||||
usetime += GET_SLEEP;
|
||||
|
||||
if(usetime > out)
|
||||
{
|
||||
msg << "GetConnFromPool Timeout." << usetime << "," << out <<
|
||||
"," << time(NULL) -t;
|
||||
LOG(LERR, msg.str().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (r == NULL);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CDBConnPool::ReleaseConnToPool( DataBase * t, bool success )
|
||||
{
|
||||
//pthread_mutex_lock(&m_mutex);
|
||||
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.find(t);
|
||||
if( iter != m_poolmap.end() )
|
||||
{
|
||||
if(iter->second==CDBConnPool::POOL_USE)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
iter->second=CDBConnPool::POOL_FREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream msg;
|
||||
iter->second=CDBConnPool::POOL_ERR;
|
||||
msg << "DB Pool used failed.";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool CDBConnPool::IsTimeoutAlive()
|
||||
{
|
||||
bool r = false;
|
||||
pthread_mutex_lock(&m_alivemutex);
|
||||
struct timespec to;
|
||||
|
||||
if(m_alivetime > 0 )
|
||||
to.tv_sec = time(NULL) + m_alivetime;
|
||||
else
|
||||
to.tv_sec = time(NULL) + 5;
|
||||
|
||||
to.tv_nsec = 0;
|
||||
|
||||
int err = pthread_cond_timedwait(&m_alivecond, &m_alivemutex, &to);
|
||||
|
||||
if (err == ETIMEDOUT)
|
||||
{
|
||||
if( m_alivetime > 0 )
|
||||
r = true;
|
||||
}
|
||||
else if ( err == 0 )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "Set Keep alive Timeout : " << m_alivetime << endl;
|
||||
#endif //_DEBUG
|
||||
r = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_alivemutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CDBConnPool::SendAliveMsg()
|
||||
{
|
||||
ostringstream msg;
|
||||
ostringstream sql;
|
||||
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.begin();
|
||||
map<DataBase*, short>::iterator enditer = m_poolmap.end();
|
||||
|
||||
sql << "SELECT sp_user_seq, sp_svc_tran_id FROM t_sms_sp_svc_product LIMIT 1";
|
||||
while(iter != enditer)
|
||||
{
|
||||
DataBase * d = iter->first;
|
||||
if(iter->second == CDBConnPool::POOL_FREE)
|
||||
{
|
||||
iter->second = CDBConnPool::POOL_USE;
|
||||
d->PgDoExec( const_cast<char*> (sql.str().c_str()) );
|
||||
if( d->PgResult(DataBase::CLEAR) < 0 )
|
||||
{
|
||||
msg << "Send alive : message failed : " << iter->first->GetErrorMessage();
|
||||
LOG(LERR, msg.str().c_str());
|
||||
iter->second=CDBConnPool::POOL_ERR;
|
||||
iter++;
|
||||
//m_poolmap.erase(iter++);
|
||||
//delete d;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->second = CDBConnPool::POOL_FREE;
|
||||
msg << "Send alive : message success.";
|
||||
LOG(LDEV1, msg.str().c_str());
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
else if (iter->second == CDBConnPool::POOL_ERR)
|
||||
{
|
||||
msg << "Send alive : Error Pool remove.";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
m_poolmap.erase(iter++);
|
||||
delete d;
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* CDBConnPool::KeepPoolAlive( void* pdata )
|
||||
{
|
||||
CDBConnPool* pObject = reinterpret_cast<CDBConnPool *>(pdata);
|
||||
ostringstream msg;
|
||||
|
||||
while( pObject->IsExit() == false )
|
||||
{
|
||||
bool b = pObject->IsTimeoutAlive();
|
||||
msg << "KeepPoolAlive Timeout - run : " << b;
|
||||
LOG(LDEV1, msg.str().c_str());
|
||||
if( pObject->IsExit() == false && b )
|
||||
{
|
||||
// send keep alive message
|
||||
pObject->SendAliveMsg();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CDBConnPool::SetKeepAliveTimeout(int sec)
|
||||
{
|
||||
m_alivetime = sec;
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
return m_alivetime;
|
||||
}
|
||||
|
||||
int CDBConnPool::GetFreePoolCnt()
|
||||
{
|
||||
int r = 0;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
// pthread_mutex_lock(&m_mutex);
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == CDBConnPool::POOL_FREE)
|
||||
{
|
||||
r++;
|
||||
}
|
||||
}
|
||||
// pthread_mutex_unlock(&m_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
// 2014.06.06 dadamin
|
||||
// 현재 DB 형상 체크
|
||||
bool CDBConnPool::SetTargetTableType(DataBase * d)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
if (d == NULL)
|
||||
return false;
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
if (d->GetNoTuples() > 0)
|
||||
{
|
||||
m_tabletype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tabletype = 1;
|
||||
}
|
||||
|
||||
d->PgClear();
|
||||
msg << "Set Target Table Type : " << m_tabletype;
|
||||
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// 작업할 메타 테이블명
|
||||
string CDBConnPool::GetMetaTableName(const char * tranid)
|
||||
{
|
||||
string r;
|
||||
|
||||
switch (m_tabletype)
|
||||
{
|
||||
case 1:
|
||||
r = "t_meta_";
|
||||
r += tranid;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
r = "t_dav_resource";
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(LDBG, "Working Table Name %s", r.c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CDBConnPool::printstatus(string prefixed)
|
||||
{
|
||||
int f = 0, u = 0;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
|
||||
if(m_exitpool == true ) return;
|
||||
// pthread_mutex_lock(&m_mutex);
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == CDBConnPool::POOL_FREE)
|
||||
{
|
||||
f++;
|
||||
}
|
||||
else
|
||||
{
|
||||
u++;
|
||||
}
|
||||
}
|
||||
|
||||
ostringstream msg;
|
||||
if( prefixed.empty() == false )
|
||||
msg << "["<< prefixed <<"]";
|
||||
|
||||
msg <<"DB connection Pool - " <<"total : " << m_poolmap.size() << "(" << u <<
|
||||
"/" << f << ")";
|
||||
|
||||
LOG(LINF, msg.str().c_str());
|
||||
}
|
||||
|
||||
// master db pool
|
||||
CMasterDBPool::CMasterDBPool(CDataBaseInfo info)
|
||||
: CDBConnPool(info)
|
||||
{
|
||||
}
|
||||
|
||||
CMasterDBPool::~CMasterDBPool()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void CMasterDBPool::init(CDataBaseInfo info)
|
||||
{
|
||||
if( CMasterDBPool::m_inst == NULL )
|
||||
{
|
||||
CMasterDBPool::m_inst = new CMasterDBPool(info);
|
||||
}
|
||||
}
|
||||
|
||||
CMasterDBPool* CMasterDBPool::getInstance()
|
||||
{
|
||||
return CMasterDBPool::m_inst;
|
||||
}
|
||||
|
||||
int CMasterDBPool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if( CMasterDBPool::m_inst != NULL )
|
||||
{
|
||||
r = CMasterDBPool::m_inst->DestroyPool();
|
||||
delete CMasterDBPool::m_inst;
|
||||
CMasterDBPool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// slave db pool
|
||||
CSlaveDBPool::CSlaveDBPool(CDataBaseInfo info)
|
||||
: CDBConnPool(info)
|
||||
{
|
||||
}
|
||||
|
||||
CSlaveDBPool::~CSlaveDBPool()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void CSlaveDBPool::init(CDataBaseInfo info)
|
||||
{
|
||||
if( CSlaveDBPool::m_inst == NULL )
|
||||
{
|
||||
CSlaveDBPool::m_inst = new CSlaveDBPool(info);
|
||||
}
|
||||
}
|
||||
|
||||
CSlaveDBPool* CSlaveDBPool::getInstance()
|
||||
{
|
||||
return CSlaveDBPool::m_inst;
|
||||
}
|
||||
|
||||
int CSlaveDBPool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if(CSlaveDBPool::m_inst != NULL )
|
||||
{
|
||||
r = CSlaveDBPool::m_inst->DestroyPool();
|
||||
delete CSlaveDBPool::m_inst;
|
||||
CSlaveDBPool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/***************************************************************************
|
||||
Database Connection Pool
|
||||
-----------------------------------------
|
||||
begin : 2012/05/13
|
||||
copyright : (C) 2011 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.1.0
|
||||
|
||||
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.
|
||||
***************************************************************************/
|
||||
#ifndef __DATABASE_CONNECTION_POOL__
|
||||
#define __DATABASE_CONNECTION_POOL__
|
||||
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class DataBase;
|
||||
|
||||
class CDataBaseInfo
|
||||
{
|
||||
public:
|
||||
CDataBaseInfo() {}
|
||||
~CDataBaseInfo() {}
|
||||
public:
|
||||
string m_hostaddr;
|
||||
int m_port;
|
||||
string m_dbname;
|
||||
string m_user;
|
||||
string m_pw;
|
||||
};
|
||||
|
||||
class CDBConnPool
|
||||
{
|
||||
public:
|
||||
enum POOL_STATUSE
|
||||
{
|
||||
POOL_ERR = -1,
|
||||
POOL_FREE = 0,
|
||||
POOL_USE = 1
|
||||
};
|
||||
public:
|
||||
CDBConnPool(CDataBaseInfo info);
|
||||
virtual ~CDBConnPool();
|
||||
|
||||
int CreatePool( int poolcnt = 4 );
|
||||
int ReCreatePool( int poolcnt = 4 );
|
||||
int DestroyPool();
|
||||
DataBase* GetConnFromPool(int timeout = 10);
|
||||
void ReleaseConnToPool(DataBase * t, bool success = true);
|
||||
int SetKeepAliveTimeout(int sec);
|
||||
|
||||
void printstatus(string prefixed = "");
|
||||
|
||||
int GetFreePoolCnt();
|
||||
|
||||
bool IsExit() { return m_exitpool; }
|
||||
bool IsTimeoutAlive();
|
||||
bool SendAliveMsg();
|
||||
|
||||
void SetCDataBaseInfo(CDataBaseInfo info) { m_dbinfo = info; }
|
||||
CDataBaseInfo GetCDataBaseInfo() { return m_dbinfo; }
|
||||
size_t GetPoolSize() { return m_poolmap.size(); }
|
||||
|
||||
// 2014.06.06 dadamin
|
||||
// 현재 DB 형상 체크
|
||||
bool SetTargetTableType(DataBase * d);
|
||||
// 작업할 메타 테이블명
|
||||
string GetMetaTableName(const char * tranid);
|
||||
// display_name 컬럼 사용 유무
|
||||
bool UseDisplayname() {return (m_tabletype == 1); }
|
||||
|
||||
private:
|
||||
static void* KeepPoolAlive(void*);
|
||||
|
||||
private:
|
||||
CDataBaseInfo m_dbinfo;
|
||||
map<DataBase*, short> m_poolmap;
|
||||
pthread_mutex_t m_mutex;
|
||||
bool m_exitpool;
|
||||
DataBase* m_lastset;
|
||||
|
||||
int m_alivetime;
|
||||
pthread_t m_keepalive;
|
||||
pthread_cond_t m_alivecond;
|
||||
pthread_mutex_t m_alivemutex;
|
||||
|
||||
// 2014.06.04 dadamin
|
||||
// -1: unset, 0: t_dav_resource, 1: t_meat_[sp_svc_tran_id]
|
||||
int m_tabletype;
|
||||
|
||||
int m_poolsize;
|
||||
};
|
||||
|
||||
class CMasterDBPool : public CDBConnPool
|
||||
{
|
||||
public:
|
||||
static void init(CDataBaseInfo info);
|
||||
static CMasterDBPool* getInstance();
|
||||
static int release();
|
||||
|
||||
private:
|
||||
CMasterDBPool(CDataBaseInfo info);
|
||||
~CMasterDBPool();
|
||||
|
||||
private:
|
||||
static CMasterDBPool* m_inst;
|
||||
};
|
||||
|
||||
class CSlaveDBPool : public CDBConnPool
|
||||
{
|
||||
public:
|
||||
static void init(CDataBaseInfo info);
|
||||
static CSlaveDBPool* getInstance();
|
||||
static int release();
|
||||
|
||||
private:
|
||||
CSlaveDBPool(CDataBaseInfo info);
|
||||
~CSlaveDBPool();
|
||||
|
||||
private:
|
||||
static CSlaveDBPool* m_inst;
|
||||
};
|
||||
|
||||
#endif // __DATABASE_CONNECTION_POOL__
|
||||
@@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
CDataFile
|
||||
-----------------------------------------
|
||||
begin : 2011/10/28
|
||||
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 "DataFile.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// 임시 버퍼 최대 크기
|
||||
#define MAX_BUFFER_SIZE 2048
|
||||
|
||||
|
||||
CDataFile::CDataFile()
|
||||
{
|
||||
}
|
||||
|
||||
CDataFile::~CDataFile()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDataFile::Init(const char* path, bool chkdir /*= true*/)
|
||||
{
|
||||
ostringstream msg;
|
||||
// 변수 유효성 검사.
|
||||
if( path == NULL || strlen( path ) == 0 )
|
||||
{
|
||||
msg << "Wrong path info(" << path << ")";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 변수 정보 Setup
|
||||
if (strlen(path) > 0)
|
||||
{
|
||||
m_strFilePath.clear();
|
||||
m_strFileName.clear();
|
||||
|
||||
string strFullPath(path);
|
||||
int nFind = strFullPath.rfind("/") + 1;
|
||||
m_strFilePath = strFullPath.substr(0, nFind-1);
|
||||
m_strFileName = strFullPath.substr(nFind, strFullPath.size() - nFind);
|
||||
}
|
||||
|
||||
LOG(LDBG, "Data File %s, %s", m_strFilePath.c_str(), m_strFileName.c_str());
|
||||
if(m_strFilePath.size() <= 0 && m_strFileName.size() <= 0)
|
||||
{
|
||||
msg << "Wrong path info(" << path << ")";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chkdir)
|
||||
{
|
||||
// FLOW상 중복파일이 발생할 수 없지만.. 혹시 생기면 전체 데이터에 영향을 줄 수 있기때문에 방어 코드 삽입
|
||||
Delete();
|
||||
|
||||
struct stat dirStat;
|
||||
// 디렉토리 정보 검사
|
||||
if (lstat(m_strFilePath.c_str(), &dirStat) != 0)
|
||||
{
|
||||
// Directory 가 존재하지 않는 경우 Directory 생성 시도
|
||||
if (mkdir(m_strFilePath.c_str(), 0755) != 0)
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
msg << "DataFile directory create failed : [" << path << "]";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG(LDBG, "check CDataFile::Init");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDataFile::Write(const char* fmt, ...)
|
||||
{
|
||||
if(m_strFilePath.size() <= 0 || m_strFileName.size() <= 0)
|
||||
return false;
|
||||
|
||||
// DataFile file open
|
||||
FILE* pFile = NULL;
|
||||
string strFullName = m_strFilePath + "/" +m_strFileName;
|
||||
|
||||
pFile = fopen( strFullName.c_str(), "a+" );
|
||||
if( pFile == NULL )
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "DataFile file open fail : [" << strFullName << "]";
|
||||
LOG(LERR, msg.str().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// Write to DataFile file
|
||||
if(strlen(buffer) > 0)
|
||||
fprintf( pFile, "%s\n", buffer );
|
||||
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDataFile::Delete()
|
||||
{
|
||||
if(m_strFilePath.size() <= 0 || m_strFileName.size() <= 0)
|
||||
return false;
|
||||
|
||||
string strFullName = m_strFilePath + m_strFileName;
|
||||
|
||||
bool bReturn = Delete(strFullName.c_str());
|
||||
|
||||
if(bReturn)
|
||||
{
|
||||
m_strFilePath.clear();
|
||||
m_strFileName.clear();
|
||||
}
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
bool CDataFile::Delete(const char* path)
|
||||
{
|
||||
// 변수 유효성 검사.
|
||||
if(path == NULL || strlen(path) == 0)
|
||||
return false;
|
||||
|
||||
struct stat dirStat;
|
||||
// 디렉토리 정보 검사
|
||||
if(lstat(path, &dirStat ) == 0)
|
||||
{
|
||||
remove(path);
|
||||
|
||||
ostringstream msg;
|
||||
msg << "DataFile file delete success : [" << path << "]";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "DataFile file delete failed : [" << path << "]";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
CDataFile
|
||||
-----------------------------------------
|
||||
begin : 2011/10/28
|
||||
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.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __LIBRARY_DATAFILE_H__
|
||||
#define __LIBRARY_DATAFILE_H__
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CDataFile
|
||||
{
|
||||
private:
|
||||
string m_strFilePath;
|
||||
string m_strFileName;
|
||||
|
||||
public:
|
||||
CDataFile();
|
||||
~CDataFile();
|
||||
|
||||
bool Init(const char* path, bool chkdir = true);
|
||||
bool Write(const char* fmt, ...);
|
||||
bool Delete();
|
||||
bool Delete(const char* path);
|
||||
|
||||
inline string GetFilePath()
|
||||
{ return m_strFilePath; }
|
||||
|
||||
inline string GetFileName()
|
||||
{ return m_strFileName; }
|
||||
};
|
||||
|
||||
#endif /* __LIBRARY_DATAFILE_H__ */
|
||||
@@ -0,0 +1,180 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/09
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2010 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
DataBase::~DataBase()
|
||||
{
|
||||
if(m_PGconn != NULL) {
|
||||
PgCloseDB();
|
||||
}
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout)
|
||||
{
|
||||
ostringstream conninfo;
|
||||
|
||||
conninfo << "host=" << strHost << " port=" << Port << " dbname=" << strDBName <<
|
||||
" user=" << strAcct << " password=" << strPasswd << " connect_timeout=" << timeout <<
|
||||
" application_name=" << PROG_NAME;
|
||||
#ifdef _USE_LIBPQ_KEEPALIVE
|
||||
// This option is supported by at least 9.1.2. and Currently supports Linux systems.
|
||||
conninfo <<" keepalives=1";
|
||||
#endif // _USE_LIBPQ_KEEPALIVE
|
||||
//m_PGconn = PQsetdbLogin(strHost.c_str(), szPort, NULL, NULL, strDBName.c_str(), strAcct.c_str(), strPasswd.c_str());
|
||||
m_PGconn = PQconnectdb(conninfo.str().c_str());
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
PGconn *DataBase::PgOpenDB(const char *pszDBName)
|
||||
{
|
||||
m_PGconn = PQsetdb(NULL, NULL, NULL, NULL, pszDBName);
|
||||
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
|
||||
return NULL;
|
||||
}
|
||||
return m_PGconn;
|
||||
}
|
||||
|
||||
void DataBase::PgCloseDB()
|
||||
{
|
||||
if(m_PGconn != NULL)
|
||||
{
|
||||
PQfinish(m_PGconn);
|
||||
m_PGconn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int DataBase::PgResult(CFLAG flag)
|
||||
{
|
||||
int fRet = 0;
|
||||
int Result;
|
||||
|
||||
Result = PQresultStatus(m_pRes);
|
||||
switch(Result) {
|
||||
case PGRES_EMPTY_QUERY :
|
||||
fRet = -1;
|
||||
break;
|
||||
case PGRES_BAD_RESPONSE :
|
||||
fRet = -2;
|
||||
break;
|
||||
case PGRES_NONFATAL_ERROR :
|
||||
fRet = -3;
|
||||
break;
|
||||
case PGRES_FATAL_ERROR :
|
||||
fRet = -4;
|
||||
break;
|
||||
case PGRES_TUPLES_OK :
|
||||
fRet = 1;
|
||||
break;
|
||||
case PGRES_COMMAND_OK :
|
||||
fRet = 2;
|
||||
break;
|
||||
}
|
||||
if(fRet < 0) {
|
||||
m_ErrorMessage = PQresultErrorMessage(m_pRes);
|
||||
}
|
||||
m_ResultCode = Result;
|
||||
if(flag == CLEAR && m_pRes) {
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
return fRet;
|
||||
}
|
||||
|
||||
string &DataBase::GetErrorMessage()
|
||||
{
|
||||
return m_ErrorMessage;
|
||||
}
|
||||
|
||||
int DataBase::GetCmdTuples()
|
||||
{
|
||||
//fprintf(stderr, "DataBase::GetCmdTuples PQcmdTuples %s\n", PQcmdTuples(m_pRes));
|
||||
return (int)atoi(PQcmdTuples(m_pRes));
|
||||
}
|
||||
|
||||
int DataBase::GetNoTuples()
|
||||
{
|
||||
return PQntuples(m_pRes);
|
||||
}
|
||||
|
||||
int DataBase::GetNoFields()
|
||||
{
|
||||
return PQnfields(m_pRes);
|
||||
}
|
||||
|
||||
PGresult *DataBase::GetRes()
|
||||
{
|
||||
return m_pRes;
|
||||
}
|
||||
|
||||
void DataBase::PgClear()
|
||||
{
|
||||
if(m_pRes)
|
||||
{
|
||||
PQclear(m_pRes);
|
||||
m_pRes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *DataBase::GetValue(int tuple, int field)
|
||||
{
|
||||
return PQgetvalue(m_pRes, tuple, field);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery)
|
||||
{
|
||||
return this->PgDoExec(pszQuery, NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(string &strQuery)
|
||||
{
|
||||
return this->PgDoExec((char *)strQuery.c_str(), NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(char *pszQuery, CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexec(m_PGconn, pszQuery);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
}
|
||||
|
||||
int DataBase::PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag)
|
||||
{
|
||||
if(m_PGconn == NULL) return -1;
|
||||
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
|
||||
m_pRes = PQexecParams(m_PGconn, pszQuery, nParamCnt, NULL, paramValues, NULL, NULL, 0);
|
||||
int r = PgResult(flag);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
int DataBase::PgEscapeString(char *to, const char *from, size_t length)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
//PQescapeStringConn(m_PGconn, to, from, length, &retval);
|
||||
PQescapeString(to, from, length);
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/***************************************************************************
|
||||
Database Class
|
||||
-----------------------------------------
|
||||
begin : 2010/03/11
|
||||
copyright : (C) 2010 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2010 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.
|
||||
***************************************************************************/
|
||||
#ifndef __DATABASE_H__
|
||||
#define __DATABASE_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#define MaxSizeOfDBQuery 1024*9
|
||||
|
||||
using namespace std;
|
||||
class DataBase
|
||||
{
|
||||
public:
|
||||
enum CFLAG { CLEAR = 1, NOT_CLEAR };
|
||||
DataBase() { m_PGconn = NULL; m_pRes = NULL;}
|
||||
~DataBase();
|
||||
PGconn *PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout = 10);
|
||||
PGconn *PgOpenDB(const char *pszDBName);
|
||||
void PgCloseDB();
|
||||
int PgResult(CFLAG flag);
|
||||
PGconn *GetPgConn(){ return m_PGconn;}
|
||||
PGresult *GetRes();
|
||||
void SetRes(PGresult * v) {m_pRes = v;}
|
||||
int GetCmdTuples();
|
||||
int GetNoTuples();
|
||||
int GetNoFields();
|
||||
int GetResultCode() { return m_ResultCode; }
|
||||
char *GetValue(int tuple, int field);
|
||||
void PgClear();
|
||||
int PgDoExec(string &strQuery);
|
||||
int PgDoExec(char *pszQuery);
|
||||
int PgDoExec(char *pszQuery, CFLAG flag);
|
||||
int PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag = NOT_CLEAR);
|
||||
int PgEscapeString(char *to, const char *from, size_t length);
|
||||
string &GetErrorMessage();
|
||||
private:
|
||||
int m_ResultCode;
|
||||
PGconn *m_PGconn;
|
||||
PGresult *m_pRes;
|
||||
string m_ErrorMessage;
|
||||
};
|
||||
|
||||
#endif // ~__DATABASE_H__
|
||||
@@ -0,0 +1,238 @@
|
||||
#include "ExecCall.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <spawn.h>
|
||||
|
||||
static int getCommand(string cmd, string & out)
|
||||
{
|
||||
string data;
|
||||
FILE *stream;
|
||||
int MAX_BUFFER = 256;
|
||||
char buffer[MAX_BUFFER];
|
||||
cmd.append(" 2>&1");
|
||||
LOG(LDEV1, "[POPNE] OPEN %s ", cmd.c_str());
|
||||
|
||||
stream = popen(cmd.c_str(), "r");
|
||||
if (!stream)
|
||||
{
|
||||
LOG(LERR, "[POPNE] popen error. [%s] ", cmd.c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG(LDEV1, "[POPNE] READ %s ", cmd.c_str());
|
||||
memset(buffer, 0, MAX_BUFFER);
|
||||
while (fgets(buffer, MAX_BUFFER, stream))
|
||||
{
|
||||
LOG(LDEV1, "[POPNE] READING.. %s|%s ", cmd.c_str(), buffer);
|
||||
data.append(buffer);
|
||||
memset(buffer, 0, MAX_BUFFER);
|
||||
}
|
||||
LOG(LDEV1, "[POPNE] READ END %s ", cmd.c_str());
|
||||
|
||||
if (ferror(stream))
|
||||
{
|
||||
// Handle error.
|
||||
LOG(LERR, "[POPNE] Handle error. [%s] ", cmd.c_str());
|
||||
return -2;
|
||||
}
|
||||
|
||||
out = data;
|
||||
|
||||
pclose(stream);
|
||||
//if (status == -1)
|
||||
//{
|
||||
// LOG(LERR, "[POPNE] popen run error(%s). [%s] ", data.c_str(),cmd.c_str());
|
||||
// return -3;
|
||||
//}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int callAnother(char *argv[])
|
||||
{
|
||||
|
||||
//pid_t processID;
|
||||
|
||||
//int status = -1;
|
||||
//status = posix_spawn(&processID, argv[0], NULL, NULL, argv, environ);
|
||||
|
||||
//if (status == 0)
|
||||
// LOG(LDBG, "%s Launching Application", argv[0]);
|
||||
//else
|
||||
// LOG(LDBG, "%s Launching application Failed", argv[0]);
|
||||
|
||||
///*
|
||||
pid_t pid = fork();
|
||||
|
||||
// 실해된 프로세스 좀비 프로스세 막기 위해서
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
switch (pid)
|
||||
{
|
||||
case -1:
|
||||
LOG(LERR, "Command fork failed.[%s]", argv[0]);
|
||||
return -1;
|
||||
break;
|
||||
case 0:
|
||||
{
|
||||
// exec ... call
|
||||
// close-exec
|
||||
int flags;
|
||||
for (int i = getdtablesize(); i-- > 3;) {
|
||||
if ((flags = fcntl(i, F_GETFD)) != -1)
|
||||
fcntl(i, F_SETFD, flags | FD_CLOEXEC);
|
||||
}
|
||||
execvp(argv[0], const_cast<char**>(argv));
|
||||
LOG(LERR, "Command exec failed.[%s]", argv[0]); // //check for error in execl
|
||||
exit(EXIT_FAILURE);
|
||||
return -2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// wait((int*)0);// child 종료 될 때까지 기다림; block 됨
|
||||
LOG(LDBG, "%s completed", argv[0]);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
//*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
CExecCall::CExecCall(CSyncInfo & info)
|
||||
: m_info(info)
|
||||
{
|
||||
}
|
||||
|
||||
CExecCall::~CExecCall()
|
||||
{
|
||||
}
|
||||
|
||||
int CExecCall::Call(Call_TYPE t, bool called /*= true*/)
|
||||
{
|
||||
int r = -1 ;
|
||||
switch (t)
|
||||
{
|
||||
case CExecCall::DIFF_SCRIPT:
|
||||
r = DIFF(called);
|
||||
break;
|
||||
case CExecCall::RC_CMOVE:
|
||||
r = RCCMove(called);
|
||||
break;
|
||||
default:
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CExecCall::GetFileLine(const char * filename)
|
||||
{
|
||||
int64_t r = -1;
|
||||
string out;
|
||||
ostringstream cmd, msg;
|
||||
|
||||
cmd << "cat " << filename << " | wc -l";
|
||||
if(getCommand(cmd.str(), out) == 0)
|
||||
{
|
||||
r = atoll(out.c_str());
|
||||
}
|
||||
|
||||
msg << "file lines : " << filename << " => " << r;
|
||||
_LOG(LDBG, msg.str().c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CExecCall::DIFF(bool called /*= true*/)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
// /user/service/etc/svcsync_diff.sh [master data] [slave data] [output file]
|
||||
string strCmd = CServiceConfig::GetInstance()->GetDiffCommand();
|
||||
|
||||
struct stat fileStat;
|
||||
if (stat(strCmd.c_str(), &fileStat) < 0)
|
||||
{
|
||||
LOG(LERR, "Diff Commnad not found.[%s]", strCmd.c_str());
|
||||
if (getppid() > 1)
|
||||
{
|
||||
kill(getppid(), SIGTERM);
|
||||
}
|
||||
return -101;
|
||||
}
|
||||
|
||||
strCmd = strCmd + " " + m_info.file_master_name + " " + m_info.file_slave_name + " " + m_info.file_diff_name;
|
||||
|
||||
if (called)
|
||||
{
|
||||
string out;
|
||||
r = getCommand(strCmd, out);
|
||||
|
||||
if (r != 0)
|
||||
LOG(LERR, "Fialed diff script.[%s]", strCmd.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
r = -100;
|
||||
LOG(LNOT, "Only block run diff script.[%s]", strCmd.c_str());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CExecCall::RCCMove(bool called /*= true*/)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
// /user/service/bin/rc_cmove -m copy -f [sync file]
|
||||
string strCmd = CServiceConfig::GetInstance()->GetRCCMoveCommand();
|
||||
|
||||
struct stat fileStat;
|
||||
if (stat(strCmd.c_str(), &fileStat) < 0)
|
||||
{
|
||||
LOG(LERR, "RC MOVE Commnad not found.[%s]", strCmd.c_str());
|
||||
if (getppid() > 1)
|
||||
{
|
||||
kill(getppid(), SIGTERM);
|
||||
}
|
||||
return -101;
|
||||
}
|
||||
|
||||
if (called)
|
||||
{
|
||||
strCmd = strCmd + " -m copy -f " + m_info.file_sync_name;
|
||||
string out;
|
||||
r = getCommand(strCmd, out);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *argv[8];
|
||||
argv[0] = (char *)strCmd.c_str();
|
||||
argv[1] = (char *)"-m";
|
||||
argv[2] = (char *)"copy";
|
||||
argv[3] = (char *)"-f";
|
||||
argv[4] = (char *)m_info.file_sync_name.c_str();
|
||||
argv[5] = (char *)"2>&1";
|
||||
argv[6] = (char *)"&";
|
||||
argv[7] = NULL;
|
||||
|
||||
r = callAnother(argv);
|
||||
}
|
||||
|
||||
if (r != 0)
|
||||
LOG(LERR, "Fialed rc_cmove.[%s]", strCmd.c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
exec system Wrapper Class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __EXEC_CALL_H__
|
||||
#define __EXEC_CALL_H__
|
||||
|
||||
#include "SyncList.h"
|
||||
|
||||
class CExecCall
|
||||
{
|
||||
public:
|
||||
enum Call_TYPE
|
||||
{
|
||||
DIFF_SCRIPT = 0,
|
||||
RC_CMOVE = 1
|
||||
};
|
||||
|
||||
CExecCall(CSyncInfo & info);
|
||||
~CExecCall();
|
||||
|
||||
// 외부 명령어 수행 함수
|
||||
// @param t : 수행 명령어 종류(Call_TYPE 참조)
|
||||
// called : 수행 명령어 완료 대기(true: 수행 명령어 종료 대기, flase : 명령만 수행)
|
||||
// @return 0 : 정상 수행, 0 이외 : 비정상 수행됨
|
||||
int Call(Call_TYPE t, bool called = true);
|
||||
|
||||
// 외부 명령인 wc -l 수행 함수
|
||||
// @return 0 <= : filename 대한 wc 수행 결과 , 0 > : 비정상 수행됨
|
||||
int GetFileLine(const char * filename);
|
||||
|
||||
private:
|
||||
int DIFF(bool called = true);
|
||||
int RCCMove(bool called = true);
|
||||
|
||||
CSyncInfo m_info;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __EXEC_CALL_H__ */
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "GetSource.h"
|
||||
#include "Logger.h"
|
||||
#include "ProcessSocketControl.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "RcSyncdRequestData.h"
|
||||
|
||||
#define REQUEST_TIME_OUT_DIFF (120*60)
|
||||
#define REQUEST_TIME_OUT (5)
|
||||
|
||||
CGetSource::CGetSource(CSyncInfo &info)
|
||||
: m_syncinfo(info)
|
||||
{
|
||||
}
|
||||
|
||||
CGetSource::~CGetSource()
|
||||
{
|
||||
}
|
||||
|
||||
bool CGetSource::GetRemote()
|
||||
{
|
||||
int nResult;
|
||||
// Slave rc_syncd 접속 및 content 정보 요청
|
||||
CProcessSocketControl slave;
|
||||
if( slave.ConnectTarget(m_syncinfo.sync_rcts, CServiceConfig::GetInstance()->GetOperationPort()) == false )
|
||||
{
|
||||
_LOG( LERR, "Connect failed to slave, %s", m_syncinfo.sync_rcts.c_str() );
|
||||
}
|
||||
|
||||
CReqSlaveData request;
|
||||
request.sync_type = m_syncinfo.sync_type;
|
||||
request.start_time = m_syncinfo.start_time;
|
||||
request.end_time = m_syncinfo.end_time;
|
||||
request.master = m_syncinfo.sync_master;
|
||||
request.slave = m_syncinfo.sync_slave;
|
||||
|
||||
if( slave.SendRequestContentListToSlave( request ) == false )
|
||||
{
|
||||
// 전송 실패시
|
||||
_LOG( LERR, "ContentList request send fail.(=> slave)");
|
||||
slave.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// check request result
|
||||
// timeout check
|
||||
time_t timeStart;
|
||||
time_t timeNow;
|
||||
timeStart = time(&timeStart);
|
||||
|
||||
// 루프를 돌면서 요청에 대한 응답을 대기
|
||||
while(1)
|
||||
{
|
||||
bool bResultSuccess = false; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
|
||||
std::string strMessage; // 수신 메시지 저장 변수.
|
||||
|
||||
// diff time 120분
|
||||
if ( difftime(time(&timeNow), timeStart) > REQUEST_TIME_OUT_DIFF )
|
||||
{ // REQUEST_TIME_OUT_DIFF
|
||||
LOG(LERR, "Content List Request timeout from slave. [Master svcid:%s]", request.master.c_str());
|
||||
|
||||
slave.Close();
|
||||
return false;
|
||||
}
|
||||
// nTimeout 에 지정된 시간동안 응답대기
|
||||
nResult = slave.RecvResultContentListFromSlave( REQUEST_TIME_OUT, bResultSuccess, m_syncinfo.file_slave_name, strMessage);
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
|
||||
// 해당 내역 로깅 및 루프 종료
|
||||
_LOG( LERR, "Response wait fail by socket" );
|
||||
|
||||
slave.Close();
|
||||
return false;
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Alive Check 패킷 한번 쏘고 다시 Loop 로
|
||||
|
||||
if( slave.SendAliveCheck() == false )
|
||||
{
|
||||
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
|
||||
_LOG( LERR, "Response wait fail by socket2");
|
||||
slave.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG( LDBG, "Response wait");
|
||||
// 정상적인 경우 다시 응답대기.
|
||||
continue;
|
||||
}
|
||||
else if( nResult == 1 )
|
||||
{
|
||||
// 요청에 대한 처리결과 정보가 수신된 경우.
|
||||
// 해당 정보 로깅처리.
|
||||
|
||||
if( bResultSuccess == true )
|
||||
{
|
||||
// 요청에 대한 처리가 정상적으로 처리된 경우
|
||||
_LOG( LINF, "Sync result SUCCESS [%s]", strMessage.c_str() );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 오류 발생시
|
||||
_LOG( LINF, "Sync result ERROR [%s]", strMessage.c_str() );
|
||||
slave.Close();
|
||||
return false;
|
||||
}
|
||||
break; // 응답을 받았으니 응답 대기 루프 종료
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replication 요청에 대한 응답패킷이 아닌 경우.
|
||||
// 해당 패킷은 무시하고 다시 Loop 로
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
slave.Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGetSource::GetSelf(bool isMaster, CSourceData & self)
|
||||
{
|
||||
if (self.Init(isMaster, m_syncinfo) == false)
|
||||
{
|
||||
LOG(LERR, "Failed Source date initialization.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//// data 추출 시작
|
||||
if (self.Execute() == false)
|
||||
{
|
||||
LOG(LERR, "Failed Source date execute.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGetSource::GetSource(GET_TYPE t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case CGetSource::BOTH:
|
||||
case CGetSource::SELF_MASTER_ONLY:
|
||||
{
|
||||
int nRetry = 0;
|
||||
bool bRemoteSuccess= false;
|
||||
// master source 데이터 자기 자신
|
||||
CSourceData master;
|
||||
if (GetSelf(true, master) == false)
|
||||
{
|
||||
LOG(LERR, "Failed GetSource(Slave).");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t == CGetSource::BOTH)
|
||||
{
|
||||
// Slave에 동기화 대상 파일 요청
|
||||
do
|
||||
{
|
||||
bRemoteSuccess = GetRemote();
|
||||
if( bRemoteSuccess == true)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++nRetry;
|
||||
}while(nRetry > 3); // 재시도 3회
|
||||
}
|
||||
|
||||
//// data 추출 완료 대기
|
||||
pthread_join(*master.GetThreadHandle(), NULL);
|
||||
|
||||
if( bRemoteSuccess == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//// 작업 성공 유무 체크
|
||||
string errmsg;
|
||||
if (master.isError(errmsg) == true)
|
||||
{
|
||||
LOG(LERR, "Failed Master Source date [%s].", errmsg.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CGetSource::SELF_SLAVE_ONLYE:
|
||||
{
|
||||
CSourceData slave;
|
||||
if (GetSelf(false, slave) == false)
|
||||
{
|
||||
LOG(LERR, "Failed GetSource(Slave).");
|
||||
return false;
|
||||
}
|
||||
//// data 추출 완료 대기
|
||||
pthread_join(*slave.GetThreadHandle(), NULL);
|
||||
|
||||
//// 작업 성공 유무 체크
|
||||
string errmsg;
|
||||
if (slave.isError(errmsg) == true)
|
||||
{
|
||||
LOG(LERR, "Failed Source date [%s].", errmsg.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(LERR, "Unknown GetSouce Type.");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
Get Source Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __GET_SOURCE_H__
|
||||
#define __GET_SOURCE_H__
|
||||
|
||||
#include "SyncList.h"
|
||||
#include "SourceData.h"
|
||||
|
||||
class CGetSource
|
||||
{
|
||||
public:
|
||||
enum GET_TYPE
|
||||
{
|
||||
BOTH = 0, // (local Master, remove : slave)
|
||||
SELF_MASTER_ONLY = 1,
|
||||
SELF_SLAVE_ONLYE = 2
|
||||
};
|
||||
|
||||
CGetSource(CSyncInfo &info);
|
||||
~CGetSource();
|
||||
|
||||
bool GetSource(GET_TYPE t);
|
||||
|
||||
private:
|
||||
bool GetRemote();
|
||||
bool GetSelf(bool isMaster, CSourceData & self);
|
||||
|
||||
CSyncInfo m_syncinfo;
|
||||
|
||||
};
|
||||
|
||||
#endif /* __GET_SOURCE_H__ */
|
||||
@@ -0,0 +1,487 @@
|
||||
#include "Main.h"
|
||||
|
||||
#include "ProcessRename.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
#include "Worker.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
// Accept 대기 Count 수
|
||||
#define DEFAULT_ACCEPT_WAIT_COUNT 50
|
||||
|
||||
// 전역 객체 정보
|
||||
// 명령 수신, Data 송수신을 담당할 TCP Listen Socket
|
||||
int g_listenSocket = -1;
|
||||
|
||||
|
||||
// 사용방법 표시
|
||||
void PrintUsage()
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Usage: " PROG_NAME " [-h] [-v] [-c {file}] \n");
|
||||
fprintf(stderr, "Options: \n");
|
||||
fprintf(stderr, " -h Display help information \n");
|
||||
fprintf(stderr, " -v Display version \n");
|
||||
fprintf(stderr, " -c {file} Use {file} as config file \n");
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, PROG_NAME " is Solbox Cloud Storage module that service - service content sync and check .\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 버전 정보 표시
|
||||
void PrintVersion()
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, PROG_NAME " version: " PROG_VERSION "\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
// 설정 파일을 저장할 변수.
|
||||
std::string strConfigFileName = DEFAULT_CONFIG_FILE;
|
||||
|
||||
// linux 에서 프로세스를 Titile 변경을 지원을 위해서 argv 메모리에 저장
|
||||
argv = save_ps_display_args(argc, argv);
|
||||
|
||||
// 전달 받은 옵션 여부 확인 및 처리
|
||||
if( argc >= 2)
|
||||
{
|
||||
int opt;
|
||||
while((opt = getopt(argc, argv, "hvc:")) != -1) // 옵션 끝까지 파싱처리
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
case 'h':
|
||||
case '?': // 정의되지 않은 문자가 나타날 경우 getopt 에 자동반환. 도움말 표시 처리.
|
||||
PrintUsage();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'v':
|
||||
PrintVersion();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
case 'c':
|
||||
strConfigFileName = optarg;
|
||||
fprintf(stderr, PROG_NAME " start with user define conf[%s]\n", strConfigFileName.c_str());
|
||||
break;
|
||||
|
||||
default: // 본 조건절은 getopt 특성상 동작하지 않지만...업무 Flow 이해(?)를 위해 유지한다.
|
||||
fprintf(stderr, "Unkonwn options[%c] used. program terminated.\n", opt);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 프로그램 중복 실행 체크
|
||||
if( IsCurrentProcessRun() == true )
|
||||
{
|
||||
fprintf(stderr, "[warning] Process[" PROG_NAME "] is already running...\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// conf 로딩 및 검사
|
||||
std::string szErrorMessage;
|
||||
if( CServiceConfig::Init( PROG_NAME, strConfigFileName, szErrorMessage ) == false)
|
||||
{
|
||||
fprintf(stderr, "[ERR] %s\n\n", szErrorMessage.c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Log 객체 생성 및 초기화
|
||||
if (CLogger::Init(PROG_NAME, CServiceConfig::GetInstance()->GetLogPath(), LINF) == false)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Log module initialize failed.[%s]\n\n", CServiceConfig::GetInstance()->GetLogPath());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Daemonize...
|
||||
// - nochdir: true(작업 디렉토리 변경 안함)
|
||||
// - noclose: false (표준 입출력, 에러를 /dev/null 로 리디렉트 처리)
|
||||
if( daemon(1, 0) == -1)
|
||||
{
|
||||
fprintf(stderr, "[ERR] Process daemonize failed.[%s]\n\n", strerror(errno) );
|
||||
|
||||
ReadyToExit();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Signal 처리기 설정
|
||||
SetSignalMain();
|
||||
|
||||
// Process 기동 관련 정보 로깅
|
||||
std::vector<std::string> vecTemp;
|
||||
std::vector< std::string >::const_iterator it;
|
||||
_LOG( LINF, "***********************************************************");
|
||||
_LOG( LINF, " %s Start. Version: %s", PROG_NAME, PROG_VERSION);
|
||||
_LOG( LINF, "***********************************************************");
|
||||
_LOG( LINF, "Config : %s", strConfigFileName.c_str());
|
||||
_LOG( LINF, "Log : %s/%s", CServiceConfig::GetInstance()->GetLogPath(), PROG_NAME);
|
||||
_LOG( LINF, "Log level : %d", CServiceConfig::GetInstance()->GetLogLevel());
|
||||
_LOG( LINF, "RC ID : %s", CServiceConfig::GetInstance()->GetRcId());
|
||||
_LOG( LINF, "RCDB : %s %u %s %s", CServiceConfig::GetInstance()->GetRcdbIp()
|
||||
, CServiceConfig::GetInstance()->GetRcdbPort()
|
||||
, CServiceConfig::GetInstance()->GetRcdbName()
|
||||
, CServiceConfig::GetInstance()->GetRcdbAcct());
|
||||
_LOG( LINF, "Skip keyword" );
|
||||
vecTemp = CServiceConfig::GetInstance()->GetSkipWord();
|
||||
for( it = vecTemp.begin(); it != vecTemp.end(); it++ )
|
||||
{
|
||||
_LOG( LINF, " : %s", it->c_str() );
|
||||
}
|
||||
_LOG( LINF, "Operation tcp port : %u", CServiceConfig::GetInstance()->GetOperationPort() );
|
||||
_LOG( LINF, "DB pool count : %u", CServiceConfig::GetInstance()->GetDbPoolCount() );
|
||||
_LOG( LINF, "Work pool count : %u", CServiceConfig::GetInstance()->GetWorkPoolCount() );
|
||||
_LOG( LINF, "Safety factor : %u (sec)", CServiceConfig::GetInstance()->GetSafetyFactor() );
|
||||
_LOG( LINF, "Once Size : %u (day)", CServiceConfig::GetInstance()->GetOnceSize() );
|
||||
_LOG( LINF, "Check" );
|
||||
_LOG( LINF, " small : %u (sec)", CServiceConfig::GetInstance()->GetChkSmall() );
|
||||
_LOG( LINF, " middle : %u (sec)", CServiceConfig::GetInstance()->GetChkMiddle() );
|
||||
_LOG( LINF, " once : %u (hour)", CServiceConfig::GetInstance()->GetChkOnce() );
|
||||
_LOG( LINF, "Diff command : %s", CServiceConfig::GetInstance()->GetDiffCommand() );
|
||||
_LOG( LINF, "***********************************************************");
|
||||
|
||||
// Log Level 재설정. -> conf 설정대로 변경 처리.
|
||||
#ifdef _DEBUG_
|
||||
CLogger::GetInstance()->SetLogLevel(LDBG);
|
||||
#else
|
||||
CLogger::GetInstance()->SetLogLevel(CServiceConfig::GetInstance()->GetLogLevel());
|
||||
#endif
|
||||
|
||||
// Command 및 Data 송수신 처리 관련 Listen Socket 생성
|
||||
if( MakeListenSocket( g_listenSocket ) == false )
|
||||
{
|
||||
LOG( LERR, "Listen socket create failed. => process exit." );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Worker Process 생성
|
||||
if( MakeProcessWorker( g_listenSocket ) == false )
|
||||
{
|
||||
LOG( LERR, "Worker process make failed. => process exit.");
|
||||
|
||||
ReadyToExit();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Process Rename
|
||||
set_ps_display(PROG_NAME": Main [monitor worker process]", false);
|
||||
|
||||
// Main Process : 그냥 대기
|
||||
while( 1 )
|
||||
{
|
||||
// Main Process 는 할 일이 없다.
|
||||
// => Worker 프로세스 종료시 SIGCHLD 신호로 인해 신호처리기에서 Worker Process 재성성 수행함.
|
||||
// => 따라서 그냥 시그널 대기
|
||||
pause();
|
||||
}
|
||||
|
||||
// 다음의 코드는 Daemon 으로 동작하기 때문에 수행되지 않는다.
|
||||
ReadyToExit();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// Command, Data 수신을 위한 TCP Listen socket 생성
|
||||
bool MakeListenSocket( int & listenSocket )
|
||||
{
|
||||
listenSocket = socket( AF_INET, SOCK_STREAM, 0 );
|
||||
if( listenSocket == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Listen socket create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in listenSockAddr;
|
||||
socklen_t listenSockLen = 0;
|
||||
memset( &listenSockAddr, 0x00, sizeof( listenSockAddr ) );
|
||||
|
||||
listenSockAddr.sin_family = AF_INET;
|
||||
listenSockAddr.sin_port = htons( CServiceConfig::GetInstance()->GetOperationPort() );
|
||||
listenSockAddr.sin_addr.s_addr = htonl( INADDR_ANY );
|
||||
|
||||
listenSockLen = sizeof( listenSockAddr );
|
||||
|
||||
int result = 0;
|
||||
|
||||
// Socket Port Reuse Option Set
|
||||
int opt = 1;
|
||||
result = setsockopt( listenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) );
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Listen socket option[SO_REUSEADDR] set failed. [%d][%s]", errorNum, strerror( errorNum ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep Alive Option set
|
||||
opt = 1;
|
||||
result = setsockopt( listenSocket, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof( opt ) );
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Listen socket option[SO_KEEPALIVE] set failed. [%d][%s]", errorNum, strerror( errorNum ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Socket Bind
|
||||
result = bind( listenSocket, ( struct sockaddr * )&listenSockAddr, listenSockLen );
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Listen socket bind failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Socket Listen
|
||||
result = listen( listenSocket, DEFAULT_ACCEPT_WAIT_COUNT );
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Listen socket listen failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Worker Process 생성(fork) 처리 함수
|
||||
// @return 생성 성공시 true, 실패시에는 false 를 반환.
|
||||
bool MakeProcessWorker( int listenSocket )
|
||||
{
|
||||
// Worker 프로세스 fork
|
||||
pid_t processId = fork();
|
||||
if( processId < 0 ) // fork fail
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Worker process create failed. [%d][%s]", errorNum, strerror(errorNum) );
|
||||
return false;
|
||||
}
|
||||
else if( processId == 0 ) // Child Process => Worker Process
|
||||
{
|
||||
// Worker Process Main 함수 호출 및 종료처리.
|
||||
int iResult;
|
||||
iResult = WorkerMain( listenSocket );
|
||||
|
||||
ReadyToExit();
|
||||
|
||||
// WorkerMain() 함수 return 값으로 종료처리되도록 한다.
|
||||
exit( iResult );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parent Process => Logging
|
||||
_LOG(LINF, "Worker[%d] create success." , processId);
|
||||
|
||||
// 잠시 대기
|
||||
solusleep(100000);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
|
||||
// @return void
|
||||
void Trim( std::string & str)
|
||||
{
|
||||
if( str.length() == 0 )
|
||||
return;
|
||||
|
||||
// 문자열 뒤의 공백, TAB, CR 등의 문자 제거처리.
|
||||
std::string::size_type pos = str.find_last_not_of(" \a\b\f\n\r\t\v");
|
||||
if( pos != std::string::npos )
|
||||
str.erase(pos + 1);
|
||||
|
||||
// 문자열 앞의 공백, TAB, CR 등의 문자 제거처리.
|
||||
pos = str.find_first_not_of(" \a\b\f\n\r\t\v");
|
||||
if( pos != std::string::npos )
|
||||
str.erase(0, pos);
|
||||
}
|
||||
|
||||
// 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
|
||||
// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
|
||||
bool IsCurrentProcessRun()
|
||||
{
|
||||
char tempBuffer[512];
|
||||
FILE * fd = NULL;
|
||||
bool bRun = false;
|
||||
|
||||
snprintf( tempBuffer, sizeof(tempBuffer), "pgrep -x %s | sort", PROG_NAME );
|
||||
|
||||
fd = popen( tempBuffer, "r" );
|
||||
if( fd == NULL )
|
||||
{
|
||||
// 오류 발생시 true 반환하여 프로세스 실행 방지처리
|
||||
fprintf(stderr, "[ERR] Process duplication check failed.[popen error][%s]\n", strerror(errno));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( tempBuffer, 0x00, sizeof(tempBuffer) );
|
||||
while( fgets( tempBuffer, sizeof(tempBuffer)-1, fd) != NULL )
|
||||
{
|
||||
string tempPid( tempBuffer );
|
||||
Trim(tempPid);
|
||||
|
||||
if( atoi( tempPid.c_str() ) != getpid() )
|
||||
{
|
||||
fprintf(stderr, "[info] Process duplication found. pid[%d]\n", atoi(tempPid.c_str()));
|
||||
bRun = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pclose( fd );
|
||||
return bRun;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 프로세스 종료 전 처리할 종료 관련 각 작업을 일괄로 처리하기 위한 함수.
|
||||
void ReadyToExit()
|
||||
{
|
||||
if( g_listenSocket != -1 )
|
||||
{
|
||||
close( g_listenSocket );
|
||||
g_listenSocket = -1;
|
||||
}
|
||||
|
||||
// Logger 객체 종료 처리.
|
||||
CLogger::Exit();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Main Process 가 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
|
||||
// @param nSignalNumber [in] 발생한 시그널 Number
|
||||
// @return void
|
||||
static void SignalMainTerminate(int nSignalNumber)
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "Main[%d] process exit by user signal[SIGTERM]. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "Main[%d] process exit by abnormal signal[%d]. Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
// KILL - Child
|
||||
kill(0, SIGTERM);
|
||||
|
||||
ReadyToExit();
|
||||
|
||||
solusleep(500000);
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Main Process 에서 자식 프로세스인 Worker Process 가 종료된 경우 시그널 처리를 위한 함수
|
||||
// @param nSignalNumber [in] 발생한 시그널 Number
|
||||
// @return void
|
||||
static void SignalWorkerDead(int nSignalNumber)
|
||||
{
|
||||
pid_t deadPid;
|
||||
int nDeadStatus;
|
||||
|
||||
while( (deadPid = waitpid(-1, &nDeadStatus, WNOHANG)) > 0 )
|
||||
{
|
||||
// Worker 프로세스가 Signal 에 의해 종료되었는가?
|
||||
if( WIFSIGNALED( nDeadStatus ) )
|
||||
{
|
||||
_LOG( LWAR, "Worker[%d] killed by signal[%d].", deadPid, WTERMSIG(nDeadStatus));
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "Worker[%d] killed. Not signal.", deadPid);
|
||||
|
||||
// Worker 프로세스가 EXIT_FAILURE 반환 ( 초기화 실패시 )
|
||||
// 해당 내역을 화면 및 로그 상에 출력하고
|
||||
// Worker 프로세스를 재생성 처리하지 않는다.
|
||||
if( WIFEXITED( nDeadStatus ) )
|
||||
{
|
||||
if( WEXITSTATUS( nDeadStatus ) == EXIT_FAILURE )
|
||||
{
|
||||
_LOG( LERR, "Worker[%d] initilaize failed.", deadPid);
|
||||
_LOG( LERR, "Main[%d] abnormally exit by worker initialize failed. Good Bye..", getpid());
|
||||
|
||||
ReadyToExit();
|
||||
|
||||
solusleep(500000);
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Worker Process 재생성 처리.
|
||||
if( MakeProcessWorker( g_listenSocket ) == false )
|
||||
{
|
||||
// Worker Process 재성성 실패시
|
||||
// 로깅 처리 후 Main 프로세스 종료 시그널 발생
|
||||
_LOG( LERR, "Worker process recreate failed. => Main process exit.");
|
||||
raise( SIGTERM );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "Worker process recreate success.");
|
||||
}
|
||||
}
|
||||
|
||||
// 오류 발생시 해당 내역 로깅
|
||||
if( deadPid < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Main process error: SIG_CHLD receive but waitpid return error[%d][%s]", errorNum, strerror(errorNum));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// @brief Main 프로세스 signal 처리 설정을 위한 함수
|
||||
/// @return void
|
||||
void SetSignalMain()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
memset(&act, 0x00, sizeof(act));
|
||||
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
// 무시 처리 signal
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Child Process 인 Worker 프로세스 종료에 대한 처리기 설정.
|
||||
act.sa_handler = SignalWorkerDead;
|
||||
sigaction( SIGCHLD, &act, NULL);
|
||||
|
||||
// 사용자 종료 또는 에러 관련 신호 처리.
|
||||
act.sa_handler = SignalMainTerminate;
|
||||
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
rc_syncd Main Header ( Main.h )
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __RC_SYNCD_MAIN_H__
|
||||
#define __RC_SYNCD_MAIN_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// 사용 방법을 화면에 표시하기 위한 함수.
|
||||
void PrintUsage(void);
|
||||
|
||||
// Version 정보를 화면에 표시하기 위한 함수
|
||||
void PrintVersion(void);
|
||||
|
||||
// Command, Data 수신을 위한 TCP Listen socket 생성
|
||||
bool MakeListenSocket( int & listenSocket );
|
||||
|
||||
// Worker Process 생성(fork) 처리 함수
|
||||
// @return 생성 성공시 true, 실패시에는 false 를 반환.
|
||||
bool MakeProcessWorker( int listenSocket );
|
||||
|
||||
// std 상에 trim 함수가 없어서 직접 구현 아니면 boost/algorithm/string.hpp 상의 boost::trim 함수 사용
|
||||
// @param str [in/out] Trim 할 문자열을 저장한 String 참조변수.
|
||||
// @return void
|
||||
void Trim( std::string & str );
|
||||
|
||||
// 현재 Process가 기동중인지 여부를 판단하기 위한 함수( 프로세스 중복 실행 체크)
|
||||
// @return 이미 해당 프로세스가 기동 중인 경우 true 반환, 그렇지 않으면 false 반환.
|
||||
bool IsCurrentProcessRun( void );
|
||||
|
||||
// 프로세스 종료에 따른 반복적인 종료 관련 작업을 수행하기 위한 함수.
|
||||
void ReadyToExit(void);
|
||||
|
||||
// Main 프로세스 signal 처리 설정을 위한 함수
|
||||
// @return void
|
||||
void SetSignalMain( void );
|
||||
|
||||
/* Signal 처리를 위한 각 Signal Handler 함수는
|
||||
* 다른 Code 에서 Include 처리시 Static 관련 문제로 인해
|
||||
* 본 Header 에서 선언처리 하지 않음. cpp 에만 존재
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RC_SYNCD_MAIN_H__ */
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#include "MakeSyncFile.h"
|
||||
#include "ExecCall.h"
|
||||
#include "WorkPool.h"
|
||||
#include "Logger.h"
|
||||
#include "Util.h"
|
||||
#include <fstream>
|
||||
|
||||
#define WORK_WAIT 1000000 // microsecond
|
||||
|
||||
static int worknotifyfn(void *object, short success)
|
||||
{
|
||||
CMakeSyncFile* o = reinterpret_cast<CMakeSyncFile *>(object);
|
||||
|
||||
return o->WorkNotify(success);
|
||||
}
|
||||
|
||||
CMakeSyncFile::CMakeSyncFile(CSyncInfo &info)
|
||||
: m_info(info), m_stop(false)
|
||||
{
|
||||
pthread_mutex_init(&m_notifymutex, NULL);
|
||||
}
|
||||
|
||||
CMakeSyncFile::~CMakeSyncFile()
|
||||
{
|
||||
m_stop = true;
|
||||
pthread_mutex_destroy(&m_notifymutex);
|
||||
}
|
||||
|
||||
bool CMakeSyncFile::MakeSyncFile()
|
||||
{
|
||||
CExecCall diff(m_info);
|
||||
|
||||
// diff
|
||||
if (diff.Call(CExecCall::DIFF_SCRIPT) != 0)
|
||||
{
|
||||
LOG(LERR, "diff data file make failed.[%s]", m_info.file_diff_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// read diff file
|
||||
m_status.m_diff = diff.GetFileLine(m_info.file_diff_name.c_str());
|
||||
if (m_status.m_diff < 0)
|
||||
{
|
||||
LOG(LERR, "Failed diff command call");
|
||||
return false;
|
||||
}
|
||||
|
||||
ifstream difffile;
|
||||
try {
|
||||
difffile.open(m_info.file_diff_name.c_str());
|
||||
if (!difffile.is_open())
|
||||
{
|
||||
LOG(LWAR, "No difference.[%s=>%s:%s~%s]",
|
||||
m_info.sync_master.c_str(), m_info.sync_slave.c_str(),
|
||||
m_info.start_time.c_str(), m_info.end_time.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ios_base::failure& e)
|
||||
{
|
||||
LOG(LERR, "diff data file open error.[%s]", m_info.file_diff_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
string line;
|
||||
while (!difffile.eof())
|
||||
{
|
||||
getline(difffile, line);
|
||||
if (line.empty() == true || line == "\r")
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "diff data read : empty or linefeed" << line << endl;
|
||||
#endif // _DEBUG
|
||||
continue;
|
||||
}
|
||||
|
||||
CWork *w = CWorkPool::getInstance()->GetWorkPool();
|
||||
if (w != NULL)
|
||||
{
|
||||
++m_status.m_work;
|
||||
// validation
|
||||
w->run(m_info, line, worknotifyfn, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_status.m_launcherfail;
|
||||
LOG(LERR, "Get Work Pool error.[%s]", line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
difffile.close();
|
||||
|
||||
// 마지막 라인에 캐리지 리턴 없는 경우 파일을 실제 읽었을 때보다
|
||||
// 한라인 작은 수를 wc -l 에서 출력되어 작업이 완료되지 않는 것을
|
||||
// 막기 위해서 work가 diff 값보다 클 때 diff 값을 work 값으로 보정
|
||||
if (m_status.m_diff < m_status.m_work)
|
||||
m_status.m_diff = m_status.m_work;
|
||||
|
||||
// end of validation
|
||||
do
|
||||
{
|
||||
if (m_status.m_diff ==
|
||||
(m_status.m_error + m_status.m_success + m_status.m_launcherfail))
|
||||
{
|
||||
LOG(LDEV1, "work end of validation");
|
||||
m_stop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
LOG(LDEV1, "working of validation.........");
|
||||
|
||||
solusleep(WORK_WAIT);
|
||||
} while (!m_stop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CMakeSyncFile::WorkNotify(short success)
|
||||
{
|
||||
pthread_mutex_lock(&m_notifymutex);
|
||||
|
||||
if (success == 0)
|
||||
{
|
||||
++m_status.m_success;
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_status.m_error;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_notifymutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
Make Sync File Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __MAKE_SYNC_FILE_H__
|
||||
#define __MAKE_SYNC_FILE_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "SyncList.h"
|
||||
|
||||
class CMakeSyncFile
|
||||
{
|
||||
public:
|
||||
CMakeSyncFile(CSyncInfo &info);
|
||||
~CMakeSyncFile();
|
||||
|
||||
bool MakeSyncFile();
|
||||
|
||||
int WorkNotify(short success);
|
||||
private:
|
||||
|
||||
class CStatus
|
||||
{
|
||||
public:
|
||||
CStatus()
|
||||
: m_diff(0), m_work(0), m_launcherfail(0), m_success(0), m_error(0) {}
|
||||
public:
|
||||
int64_t m_diff;
|
||||
int64_t m_work;
|
||||
int64_t m_launcherfail;
|
||||
int64_t m_success;
|
||||
int64_t m_error;
|
||||
};
|
||||
|
||||
CSyncInfo m_info;
|
||||
CStatus m_status;
|
||||
|
||||
bool m_stop;
|
||||
pthread_mutex_t m_notifymutex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* __MAKE_SYNC_FILE_H__ */
|
||||
@@ -0,0 +1,81 @@
|
||||
#****************************************************************************
|
||||
# Makefile for rc_syncd
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2014/09/02
|
||||
# copyright : (C) 2005 Solbox Inc.
|
||||
# author : storage dev team
|
||||
# email : storage.sd@solbox.com
|
||||
# version : 3.4
|
||||
#
|
||||
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or with out
|
||||
# modification, are not permitted in outside of Solbox Inc.
|
||||
#*****************************************************************************
|
||||
|
||||
|
||||
# Program info
|
||||
PROG_NAME = rc_syncd
|
||||
REVISION = 1422
|
||||
PROG_VERSION = 3.5.0.$(REVISION)-`date +%Y%m%d%H%M%S`
|
||||
|
||||
|
||||
DEFAULT_CONFIG_FILE = /user/service/etc/rcts.conf
|
||||
|
||||
|
||||
INSTALL_BIN = /user/service/bin
|
||||
INSTALL_CONF = /user/service/etc
|
||||
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-fno-rtti -D_REENTRANT
|
||||
|
||||
LFLAGS =
|
||||
|
||||
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\"
|
||||
|
||||
|
||||
# Application Enviroment
|
||||
APP = $(PROG_NAME)
|
||||
|
||||
DIR_INCLUDE = -I./. -I../lib -I /user/db/pgsql/include -I../
|
||||
DIR_LIB = -L../lib
|
||||
|
||||
OBJ = ServiceConfig.o ProcessStatus.o RcdbInfo.o Util.o Database.o RcSyncdClientSocket.o \
|
||||
Running.o Scheduler.o WorkPool.o DBConnPool.o SyncList.o DataFile.o SourceData.o \
|
||||
ModeMaster.o ModeSlave.o ModeSync.o RcSyncdRequest.o MasterJobThread.o\
|
||||
GetSource.o Validation.o ExecCall.o MakeSyncFile.o Synchronization.o Synchronization.o \
|
||||
ProcessSocketControl.o ClientThread.o \
|
||||
Worker.o Main.o
|
||||
|
||||
LIBS = ../lib/libInterCommon.a -lpthread -lcrypt /user/db/pgsql/lib/libpq.a
|
||||
|
||||
|
||||
############################
|
||||
|
||||
all:$(APP)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(PROG_NAME): $(OBJ)
|
||||
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core.* *.out *.log
|
||||
-rm -f $(APP)
|
||||
sync
|
||||
|
||||
|
||||
install : $(APP)
|
||||
-cp $(APP) $(INSTALL_BIN)/$(APP)
|
||||
sync
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,117 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "MasterJobThread.h"
|
||||
#include "GetSource.h"
|
||||
#include "MakeSyncFile.h"
|
||||
#include "Synchronization.h"
|
||||
|
||||
CMasterJobThread::CMasterJobThread(CSyncInfo info, CWorkResult* pResult)
|
||||
: m_info(info)
|
||||
,m_pResult(pResult)
|
||||
{
|
||||
m_threadHandle = 0;
|
||||
}
|
||||
|
||||
CMasterJobThread::~CMasterJobThread()
|
||||
{
|
||||
// Thread 동작 정지 처리
|
||||
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로 업무 Flow 수정시 주의할 것
|
||||
//if( m_threadHandle != 0 )
|
||||
//pthread_cancel( m_threadHandle );
|
||||
}
|
||||
|
||||
// thread 를 생성하여 처리 업무 flow start
|
||||
bool CMasterJobThread::Start()
|
||||
{
|
||||
int nRet = ::pthread_create( &m_threadHandle, NULL, CMasterJobThread::threadFunc, this );
|
||||
if( nRet != 0 )
|
||||
{
|
||||
// Thread 생성 실패시
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// 스레드 함수
|
||||
void* CMasterJobThread::threadFunc( void* arg )
|
||||
{
|
||||
CMasterJobThread* pObject = reinterpret_cast<CMasterJobThread *>( arg );
|
||||
|
||||
//pthread_detach( pthread_self() );
|
||||
// 실제 작업 수행.
|
||||
pObject->Execute();
|
||||
|
||||
// 생성된 파일 삭제 처리
|
||||
pObject->m_info.UnlinkFile();
|
||||
|
||||
// 객체 자동 delete 처리.
|
||||
//delete pObject;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 실제 업무 flow를 정의 한다.
|
||||
void CMasterJobThread::Execute()
|
||||
{
|
||||
string strMessage;
|
||||
// 동기화 대상 파일 수집
|
||||
CGetSource objGetSource(m_info);
|
||||
if( objGetSource.GetSource(CGetSource::BOTH) == false )
|
||||
{
|
||||
LOG( LERR, "Get Source file failed.");
|
||||
m_pResult->bSuccess = false;
|
||||
m_pResult->strMasterID = m_info.sync_master;
|
||||
m_pResult->strRcts = m_info.sync_rcts;
|
||||
m_pResult->strMessage = "Get Source file failed.";
|
||||
m_pResult->strSyncFileName = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// sync file 생성..
|
||||
CMakeSyncFile objMakeSyncfile(m_info);
|
||||
if( objMakeSyncfile.MakeSyncFile() == false )
|
||||
{
|
||||
LOG( LERR, "Sync file make failed.");
|
||||
m_pResult->bSuccess = false;
|
||||
m_pResult->strMasterID = m_info.sync_master;
|
||||
m_pResult->strRcts = m_info.sync_rcts;
|
||||
m_pResult->strMessage = "Sync file make failed.";
|
||||
m_pResult->strSyncFileName = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// sync 요청 처리.
|
||||
CSynchronization objSynchronization(m_info);
|
||||
int r = objSynchronization.ExcuteSync();
|
||||
if (r < 0 )
|
||||
{
|
||||
LOG( LERR, "Synchronization request failed.");
|
||||
m_pResult->bSuccess = false;
|
||||
m_pResult->strMasterID = m_info.sync_master;
|
||||
m_pResult->strRcts = m_info.sync_rcts;
|
||||
m_pResult->strMessage = "Synchronization request failed.";
|
||||
m_pResult->strSyncFileName = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_info.sync_type > SYNC_TYPE::NORMA_N_ONLY)
|
||||
{
|
||||
m_pResult->strMessage = "Get sync file Success.";
|
||||
// 파일명 추가
|
||||
m_pResult->strSyncFileName = r == 0 ? "" : m_info.file_sync_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pResult->strMessage = "Synchronization request Success.";
|
||||
m_pResult->strSyncFileName = "";
|
||||
}
|
||||
|
||||
m_pResult->bSuccess = true;
|
||||
m_pResult->strMasterID = m_info.sync_master;
|
||||
m_pResult->strRcts = m_info.sync_rcts;
|
||||
|
||||
LOG(LDBG, "%s", m_pResult->strMessage.c_str());
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
Synchronization Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/17
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __MASTERJOBTHREAD_H__
|
||||
#define __MASTERJOBTHREAD_H__
|
||||
|
||||
#include "ModeMaster.h"
|
||||
#include "SyncList.h"
|
||||
|
||||
class CMasterJobThread
|
||||
{
|
||||
public:
|
||||
CMasterJobThread(CSyncInfo info, CWorkResult* pResult);
|
||||
~CMasterJobThread();
|
||||
|
||||
bool Start(); //Thread 시작
|
||||
|
||||
|
||||
// 호출측에서 Thread의 종료 여부등을 판단하기 위함
|
||||
inline pthread_t GetThreadHandle()
|
||||
{ return m_threadHandle; }
|
||||
|
||||
private:
|
||||
|
||||
// 스레드 함수
|
||||
static void* threadFunc( void* arg );
|
||||
|
||||
// 쓰레드 실행 함수
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
CSyncInfo m_info;
|
||||
CWorkResult* m_pResult;
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
// client 와 통신 관련 처리를 수행하기 위한 control 객체
|
||||
CProcessSocketControl m_client;
|
||||
};
|
||||
|
||||
#endif /* __MASTERJOBTHREAD_H__ */
|
||||
@@ -0,0 +1,41 @@
|
||||
/****************************************************************************
|
||||
Service Mode Base Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SERVICE_MODE_BASE_H__
|
||||
#define __SERVICE_MODE_BASE_H__
|
||||
|
||||
#include "SyncList.h"
|
||||
#include "ProcessSocketControl.h"
|
||||
|
||||
// class CServiceMode : Service Mode Base class
|
||||
class CServiceMode
|
||||
{
|
||||
public:
|
||||
CServiceMode(CProcessSocketControl * pclient) : m_pclient(pclient) {};
|
||||
virtual ~CServiceMode(){};
|
||||
|
||||
// °¢ mode ÀÛ¾÷ ¼öÇà
|
||||
virtual void Execute() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
CProcessSocketControl * m_pclient;
|
||||
CSyncList m_synclist;
|
||||
|
||||
inline bool IsEmpytSycnList() { return m_synclist.Empty(); }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_MODE_BASE_H__ */
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "ModeMaster.h"
|
||||
#include "SourceData.h"
|
||||
#include "Logger.h"
|
||||
#include "SyncList.h"
|
||||
#include "MasterJobThread.h"
|
||||
|
||||
// class CServiceMode : Service Master Mode class
|
||||
CMasterMode::CMasterMode(CProcessSocketControl * pclient)
|
||||
: CServiceMode(pclient)
|
||||
{
|
||||
}
|
||||
|
||||
CMasterMode::~CMasterMode()
|
||||
{
|
||||
}
|
||||
|
||||
bool CMasterMode::CreateSyncList(CReqMasterData &d)
|
||||
{
|
||||
return m_synclist.CreateList(d);
|
||||
}
|
||||
|
||||
void CMasterMode::Execute()
|
||||
{
|
||||
std::string message = "";
|
||||
list<CMasterJobThread*> listThread;
|
||||
list<CWorkResult*> listWorkResult;
|
||||
bool bResult = true;
|
||||
|
||||
if (IsEmpytSycnList())
|
||||
{
|
||||
LOG(LERR, "Empty Master Mode Sync Data");
|
||||
message = "Empty Master Mode Sync Data";
|
||||
// return 처리전에 꼭 client 에 결과 전송처리할 것
|
||||
// 결과 전송하지 않으면.. 무한 대기함.
|
||||
m_pclient->SendResultSyncToClient( true, message );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CMasterJobThread *pMasterJobThread = NULL;
|
||||
while( IsEmpytSycnList() == false )
|
||||
{
|
||||
// Master job work thread 수행 결과를 받기 위한 변수
|
||||
CWorkResult* pResult = new CWorkResult;
|
||||
|
||||
CSyncInfo objSyncInfo = m_synclist.Pop();
|
||||
LOG( LDBG, "Master[%s] Slave[%s] RCTS [%s]", objSyncInfo.sync_master.c_str() , objSyncInfo.sync_slave.c_str(), objSyncInfo.sync_rcts.c_str());
|
||||
|
||||
pMasterJobThread = new CMasterJobThread(objSyncInfo, pResult);
|
||||
listWorkResult.push_back(pResult);
|
||||
// thread 구동.....
|
||||
if( pMasterJobThread->Start() == true )
|
||||
{
|
||||
listThread.push_back(pMasterJobThread);
|
||||
LOG(LDBG, "MasterJobThread start ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LINF, "MasterJobThread start failed.");
|
||||
|
||||
// 다른 sync 작업은 성공적으로 쓰레드 생성 될 수 있므로 해당 sync item만 에러 설정함
|
||||
//message = "MasterJobThread create start failed.";
|
||||
//m_pclient->SendResultSyncToClient( bResult, message );
|
||||
pResult->bSuccess = false;
|
||||
pResult->strMasterID = objSyncInfo.sync_master;
|
||||
pResult->strMessage = "MasterJob Thread create start failed.";
|
||||
if( pMasterJobThread != NULL )
|
||||
{
|
||||
delete pMasterJobThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 전체 쓰레드가 종료될때까지 대기 하기 위해서 thread join 처리
|
||||
while (!listThread.empty())
|
||||
{
|
||||
list<CMasterJobThread *>::iterator list_iter = listThread.begin();
|
||||
|
||||
CMasterJobThread * pthread = *list_iter;
|
||||
pthread_t handle = pthread->GetThreadHandle();
|
||||
LOG(LDBG, "Thread Join [%lu]", (unsigned long)handle);
|
||||
pthread_join(handle, NULL);
|
||||
LOG(LDBG, "Thread Join realese [%lu]", (unsigned long)handle);
|
||||
listThread.erase(list_iter);
|
||||
delete pthread;
|
||||
}
|
||||
|
||||
// 성공 실패 여부를 확인 하는 작업 필요.
|
||||
while (!listWorkResult.empty())
|
||||
{
|
||||
list<CWorkResult*>::iterator iter = listWorkResult.begin();
|
||||
CWorkResult* pResult = *iter;
|
||||
// 최종 성공 여부 전달 판단
|
||||
if( pResult->bSuccess == false)
|
||||
{
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
// " MasterTranid;메세지|MasterTranid;메세지|MasterTranid;메세지|MasterTranid;메세지"
|
||||
// return message 제작
|
||||
if( message.size() != 0 )
|
||||
{
|
||||
message += "|";
|
||||
}
|
||||
message += pResult->strMasterID;
|
||||
message += ";";
|
||||
message += pResult->bSuccess ? "T":"F";
|
||||
message += ";";
|
||||
message += pResult->strRcts;
|
||||
message += ";";
|
||||
message += pResult->strMessage;
|
||||
if(pResult->strSyncFileName.size() != 0)
|
||||
{
|
||||
message += ";";
|
||||
message += pResult->strSyncFileName;
|
||||
}
|
||||
|
||||
listWorkResult.erase(iter);
|
||||
delete pResult;
|
||||
}
|
||||
|
||||
// 연결된 client로 수행 작업 결과들 리턴
|
||||
m_pclient->SendResultSyncToClient( bResult, message );
|
||||
|
||||
LOG(LINF, "Result : %s", message.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
Service Master Mode Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SERVICE_MASTER_MODE_H__
|
||||
#define __SERVICE_MASTER_MODE_H__
|
||||
|
||||
#include "ModeBase.h"
|
||||
|
||||
class CWorkResult
|
||||
{
|
||||
public:
|
||||
CWorkResult(){};
|
||||
~CWorkResult(){};
|
||||
|
||||
public:
|
||||
bool bSuccess; // 성공 여부
|
||||
std::string strMasterID; // sync_master
|
||||
std::string strMessage; // error message
|
||||
std::string strRcts; // rcts info
|
||||
std::string strSyncFileName; // sync file name
|
||||
};
|
||||
|
||||
// class CServiceMode : Service Master Mode class
|
||||
class CMasterMode : public CServiceMode
|
||||
{
|
||||
public:
|
||||
CMasterMode(CProcessSocketControl * pclient);
|
||||
virtual ~CMasterMode();
|
||||
|
||||
// 요청 받은 데이터(CReqMasterData) 대한 Sync 정보 만듦
|
||||
// 함수 수행 성공일 때 Execute() 함수 수행됨
|
||||
bool CreateSyncList(CReqMasterData &d);
|
||||
|
||||
// master mode 작업 수행
|
||||
virtual void Execute();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_MASTER_MODE_H__ */
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "ModeSlave.h"
|
||||
#include "GetSource.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// class CServiceMode : Service Master Mode class
|
||||
CSlaveMode::CSlaveMode(CProcessSocketControl * pclient)
|
||||
: CServiceMode(pclient)
|
||||
{
|
||||
}
|
||||
|
||||
CSlaveMode::~CSlaveMode()
|
||||
{
|
||||
if (!IsEmpytSycnList())
|
||||
{
|
||||
m_synclist.GetFirst().UnlinkFile();
|
||||
}
|
||||
}
|
||||
|
||||
bool CSlaveMode::CreateSyncList(CReqSlaveData &d)
|
||||
{
|
||||
return m_synclist.CreateList(d);
|
||||
}
|
||||
|
||||
void CSlaveMode::Execute()
|
||||
{
|
||||
std::string strErrorMessage;
|
||||
|
||||
if (IsEmpytSycnList())
|
||||
{
|
||||
strErrorMessage = "Empty Slave Mode Sync Data";
|
||||
|
||||
// 오류 결과 전송
|
||||
m_pclient->SendErrorContentListToMaster( strErrorMessage );
|
||||
|
||||
LOG(LERR, "%s", strErrorMessage.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 수행 작업
|
||||
|
||||
// 요청 받은 정보에 대한 source data 추출
|
||||
CGetSource slave(m_synclist.GetFirst());
|
||||
if (slave.GetSource(CGetSource::SELF_SLAVE_ONLYE) == false)
|
||||
{
|
||||
strErrorMessage = "Failed Get Source Slave.";
|
||||
|
||||
// 오류 결과 전송
|
||||
m_pclient->SendErrorContentListToMaster( strErrorMessage );
|
||||
|
||||
LOG( LERR, "%s", strErrorMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// Send data : 추출된 source data ( 파일명은 file_slave_name 에 저장된 상태 )
|
||||
// - 대상 파일 size 확인...
|
||||
// - fd open 후
|
||||
// - 전송 처리.
|
||||
|
||||
struct stat resultFileStat;
|
||||
if( stat( m_synclist.GetFirst().file_slave_name.c_str(), &resultFileStat ) != 0 )
|
||||
{
|
||||
// 해당 파일에 대한 stat 정보 추출 실패시.
|
||||
int errorNum = errno;
|
||||
char tempBuffer[1024];
|
||||
snprintf( tempBuffer, sizeof( tempBuffer ) - 1, "slave mode result file[%s] stat check fail [%d][%s]"
|
||||
, m_synclist.GetFirst().file_slave_name.c_str()
|
||||
, errorNum, strerror( errorNum ) );
|
||||
|
||||
strErrorMessage = tempBuffer;
|
||||
|
||||
// 오류 결과 전송
|
||||
m_pclient->SendErrorContentListToMaster( strErrorMessage );
|
||||
|
||||
LOG( LERR, "%s", strErrorMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// 파일 size 추출.
|
||||
unsigned long long nFileSize = resultFileStat.st_size;
|
||||
|
||||
// fd open
|
||||
int resultFd = open( m_synclist.GetFirst().file_slave_name.c_str(), O_RDONLY );
|
||||
if( resultFd == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
char tempBuffer[1024];
|
||||
snprintf( tempBuffer, sizeof( tempBuffer ) - 1, "slave mode result file[%s] open fail [%d][%s]"
|
||||
, m_synclist.GetFirst().file_slave_name.c_str()
|
||||
, errorNum, strerror( errorNum ));
|
||||
|
||||
strErrorMessage = tempBuffer;
|
||||
|
||||
// 오류 결과 전송
|
||||
m_pclient->SendErrorContentListToMaster( strErrorMessage );
|
||||
|
||||
LOG( LERR, "%s", strErrorMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// 파일 전송 처리.
|
||||
if( m_pclient->SendResultContentListToMaster( resultFd, nFileSize ) == false )
|
||||
{
|
||||
// 전송 처리 실패시..
|
||||
// 상대편에서 재시도 등의 처리를 수행토록 socket 을 close 처리한다.
|
||||
LOG( LERR, "slave mode result file[%s] send fail. socket close.", m_synclist.GetFirst().file_slave_name.c_str() );
|
||||
m_pclient->Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LDBG, "slave mode result file[%s] send OK.", m_synclist.GetFirst().file_slave_name.c_str() );
|
||||
}
|
||||
|
||||
close( resultFd );
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
Service Slave Mode Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SERVICE_SLAVE_MODE_H__
|
||||
#define __SERVICE_SLAVE_MODE_H__
|
||||
|
||||
#include "ModeBase.h"
|
||||
|
||||
// class CServiceMode : Service Slave Mode class
|
||||
class CSlaveMode : public CServiceMode
|
||||
{
|
||||
public:
|
||||
CSlaveMode(CProcessSocketControl * pclient);
|
||||
virtual ~CSlaveMode();
|
||||
|
||||
// 요청 받은 데이터(CReqSlaveData) 대한 Sync 정보 만듦
|
||||
// 함수 수행 성공일 때 Execute() 함수 수행됨
|
||||
bool CreateSyncList(CReqSlaveData &d);
|
||||
|
||||
// slave mode 작업 수행
|
||||
virtual void Execute();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_SLAVE_MODE_H__ */
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "ModeSync.h"
|
||||
#include "ExecCall.h"
|
||||
#include "Logger.h"
|
||||
|
||||
// class CSyncMode : Sync Mode class
|
||||
CSyncMode::CSyncMode(CProcessSocketControl * pclient)
|
||||
: CServiceMode(pclient)
|
||||
{
|
||||
}
|
||||
|
||||
CSyncMode::~CSyncMode()
|
||||
{
|
||||
// rc_cmove 해당 파일 사용하기 때문에 정상적으로 처리되었으면 삭제되면 안됨
|
||||
//if (!IsEmpytSycnList())
|
||||
//{
|
||||
// m_synclist.GetFirst().UnlinkFile();
|
||||
//}
|
||||
}
|
||||
|
||||
bool CSyncMode::CreateSyncList(CReqSyncData &d)
|
||||
{
|
||||
return m_synclist.CreateList(d);
|
||||
}
|
||||
|
||||
void CSyncMode::Execute()
|
||||
{
|
||||
// Socket 을 통해 Master 로부터 sync 수행을 위한 파일을 수신 처리한다.
|
||||
std::string strMessage;
|
||||
if( m_pclient->RecvFileExecuteSyncFromMaster( m_synclist.GetFirst().file_sync_name, strMessage ) == false )
|
||||
{
|
||||
// sync 파일 수신 실패시...
|
||||
// - 여러 가지 상황이 발생 가능하므로...
|
||||
// - 에러 로깅 후 세션을 종료 처리한다. ( 그래야.. client 에서 재시도하므로.. )
|
||||
LOG( LERR, "Sync request file[%s] receive failed [%s]. session close."
|
||||
, m_synclist.GetFirst().file_sync_name.c_str()
|
||||
, strMessage.c_str() );
|
||||
|
||||
m_pclient->Close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Client 가 응답대기 중이므로.. rc_cmove 를 실제 수행시키기 전에 응답을 해줘야 한다.
|
||||
if (IsEmpytSycnList())
|
||||
{
|
||||
strMessage = "Empty Sync Mode Sync Data.";
|
||||
|
||||
// 오류 결과 전송
|
||||
m_pclient->SendResultExecuteSyncToMaster( false, strMessage );
|
||||
m_synclist.GetFirst().UnlinkFile();
|
||||
LOG( LERR, "%s", strMessage.c_str() );
|
||||
return;
|
||||
}
|
||||
|
||||
// 실제 rc_move 실행전에 Master 에게 정상 처리관련 응답 전송.
|
||||
// - 응답 전송 실패시.. Master 가 재시도를 하므로... 작업을 진행하지 말것.
|
||||
strMessage = "Sync job start.";
|
||||
if( m_pclient->SendResultExecuteSyncToMaster( true, strMessage ) == false )
|
||||
{
|
||||
LOG( LERR, "Send reponse (job start) fail to Master. job cancel." );
|
||||
m_synclist.GetFirst().UnlinkFile();
|
||||
return;
|
||||
}
|
||||
|
||||
// 받은 sync file을 인자로 rc_move 수행
|
||||
CExecCall rcmove(m_synclist.GetFirst());
|
||||
/// 명령 수행함 시킴
|
||||
if (rcmove.Call(CExecCall::RC_CMOVE, false) != 0)
|
||||
{
|
||||
LOG(LERR, "Failed rc_cmove call");
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/****************************************************************************
|
||||
Service Sync Mode Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SERVICE_SYNC_MODE_H__
|
||||
#define __SERVICE_SYNC_MODE_H__
|
||||
|
||||
#include "ModeBase.h"
|
||||
|
||||
|
||||
// class CSyncMode : Sync Mode class
|
||||
class CSyncMode : public CServiceMode
|
||||
{
|
||||
public:
|
||||
CSyncMode(CProcessSocketControl * pclient);
|
||||
virtual ~CSyncMode();
|
||||
|
||||
// 요청 받은 데이터(CReqSyncData) 대한 Sync 정보 만듦
|
||||
// 함수 수행 성공일 때 Execute() 함수 수행됨
|
||||
bool CreateSyncList(CReqSyncData &d);
|
||||
|
||||
// sync mode 작업 수행
|
||||
virtual void Execute();
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_SYNC_MODE_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
/***************************************************************************
|
||||
rc_syncd - rc_syncd 간의 통신 처리 담당 class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/05
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __PROCESS_SOCKET_CONTROL_H__
|
||||
#define __PROCESS_SOCKET_CONTROL_H__
|
||||
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "RcSyncdProtocol.h"
|
||||
|
||||
#include "RcSyncdRequestData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
///< BYTE 타입 정의
|
||||
#ifndef _BYTE_DEFINED
|
||||
#define _BYTE_DEFINED
|
||||
typedef unsigned char BYTE;
|
||||
#endif // _BYTE_DEFINED
|
||||
|
||||
|
||||
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // Socket 관련 data 송수신시 사용할 임시버퍼 크기.
|
||||
#define FILE_DATA_BUFFER_SIZE 16384 // 16 Kbyte, 파일 송수신시 사용할 임시 버퍼의 크기.
|
||||
|
||||
class CProcessSocketControl : public CBaseSocket
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성자.
|
||||
// socket [in] 처리할 socket descriptor
|
||||
|
||||
CProcessSocketControl();
|
||||
CProcessSocketControl( const int & socket );
|
||||
|
||||
// 소멸자.
|
||||
~CProcessSocketControl();
|
||||
|
||||
|
||||
/////// 각 업무 Flow 모듈 제공용 Interface 함수 ///////////////////
|
||||
|
||||
// 전달받은 Target 으로 Socket 접속을 수행
|
||||
// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
// @param nPort [in] 접속 Port
|
||||
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool ConnectTarget( const std::string& szTarget, int nPort );
|
||||
|
||||
// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 무시할 것.
|
||||
// @return 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendAliveCheck(void);
|
||||
|
||||
// [Master] Client 에게 Sync 요청에 대한 결과 정보 전송 처리
|
||||
// @param bSuccess [in] 성공 여부
|
||||
// @param strMessage [in] Client 로 전달할 메시지
|
||||
// @return 전송 성공시 true, 전송 실패시 false
|
||||
bool SendResultSyncToClient( bool bSuccess, std::string& strMessage );
|
||||
|
||||
// [Master] Slave rc_syncd 로 content 목록 요청.
|
||||
// @param [IN] data slave rc_syncd 로 전송할 data 객체
|
||||
// @return 전송 성공시 true, 전송 실패시 false
|
||||
bool SendRequestContentListToSlave( CReqSlaveData& data );
|
||||
|
||||
// [Master] Slave rc_syncd 에서 전송한 content 목록 정보 처리 결과를 수신하기 위한 함수.
|
||||
// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )
|
||||
// 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
// @param bSuccess [out] 성공 여부
|
||||
// 실패(false) 인 경우.. strErrorMessage 변수에 오류 내역이 저장됨
|
||||
// @param strSaveFileName [in] 성공(bSuccess==true) 인 경우... 수신된 Data 를 저장하기 위한 파일명 (Full 경로)
|
||||
// @param strErrorMessage [out] 실패(bSuccess==false) 인 경우... 수신된 오류 메시지를 저장하기 위한 변수
|
||||
// @return
|
||||
// -1 : slave rc_syncd 와 통신이 끊어진 경우.
|
||||
// 0 : slave rc_syncd 로 부터 응답을 아직 수신하지 못한 경우..
|
||||
// => AliveCheck 등의 작업 후 다시 응답 대기하면 된다.
|
||||
// 1 : 정상 응답을 수신한 경우
|
||||
// 2 : 수신된 응답이 다른 요청에 대한 응답인 경우..
|
||||
// => 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int RecvResultContentListFromSlave( int nTimeout, bool& bSuccess, std::string& strSaveFileName, std::string& strErrorMessage );
|
||||
|
||||
|
||||
// [Master] Slave rc_syncd 에 sync 작업 수행을 요청한 후 그 결과를 수신.
|
||||
// - 본 함수는 data 와 파일을 원격 rc_syncd 에 전달하여 원격 rc_syncd 가 SYNC MODE 로 동작하도록 한다.
|
||||
// 그리고.. 원격 rc_syncd 의 execute 전까지의 처리 결과를 수신하여 [out] 항목에 그 결과를 저장처리한다.
|
||||
// data [in] sync mode 수행을 위해 전달해야하는 data 객체.
|
||||
// fd [in] sync 수행 대상 content 정보를 저장한 파일에 대한 descriptor
|
||||
// nFileSize [in] sync 파일 크기
|
||||
// strMessage [out] 원격지의 sync mode 수행 관련 수신된 메시지( 정상, 실패 모두 가능)
|
||||
// return
|
||||
// true : sync 수행 요청이 정상적으로 전달되었고... 원격지 rc_syncd 가 정상 동작한 경우..
|
||||
// false : 그외 모든 오류 사항.
|
||||
bool SendRequestExecuteSyncToSlave( CReqSyncData& data, int fd, unsigned long long nFileSize, std::string& strMessage );
|
||||
|
||||
|
||||
// [Slave] Master rc_syncd 로 추출된 Content 정보 목록을 전달한다.
|
||||
// @param [IN] fd 전송할 file descripter
|
||||
// @param [IN] nFileSize 전송할 file size
|
||||
// @return 전송 성공시 true, 전송 실패시 false
|
||||
bool SendResultContentListToMaster( int fd, unsigned long long nFileSize );
|
||||
|
||||
// [Slave] Content 정보 목록 추출 실패시 Master rc_syncd 로 관련 오류 내역을 전달한다.
|
||||
// @param strMessage [IN] master rc_syncd 로 전달할 메시지
|
||||
// @return 전송 성공시 true, 전송 실패시 false
|
||||
bool SendErrorContentListToMaster( std::string& strMessage );
|
||||
|
||||
|
||||
// [Sync] Master 에게 Sync Execute 요청에 대한 응답을 전송 처리
|
||||
// @param bSuccess [in] 성공 여부
|
||||
// @param strMessage [in] 전달할 메시지
|
||||
// @return 전송 성공시 true, 전송 실패시 false
|
||||
bool SendResultExecuteSyncToMaster( bool bSuccess, std::string& strMessage );
|
||||
|
||||
|
||||
/////// 통신 관련 Client Thread 내부용 Interface 함수 ///////////////////
|
||||
|
||||
// Client 로 부터 수신된 Sync 요청 Data body 수신 처리.
|
||||
// @param request [out] 수신된 정보를 저장하기 위한 객체
|
||||
// @return 수신 성공시 true, 그 외 false
|
||||
bool RecvBodySyncFromClient( CReqMasterData& request );
|
||||
|
||||
// Master rc_syncd 에서 전송한 Content 목록 요청의 Data body 수신 처리.
|
||||
bool RecvBodyContentListFromMaster( CReqSlaveData& request );
|
||||
|
||||
// Master rc_syncd 에서 전송한 sync 실행 요청 관련 data body 수신 처리.
|
||||
// - 파일 관련 부분은 수신하지 않고.. 아래 함수(RecvFileExecuteSyncFromMaster)를 통해 따로 수신 처리해야 함.
|
||||
// @param request [in] 수신된 CReqSyncData 정보를 저장하기위한 객체
|
||||
// @return 성공시 true, 실패시 false
|
||||
bool RecvBodyExecuteSyncFromMaster( CReqSyncData& request );
|
||||
|
||||
// Master rc_syncd 에서 전송한 sync 실행 요청 관련 sync file 관련 부분을 수신 처리.
|
||||
// @param strSaveFileName [in] 저장 파일명
|
||||
// @param strErrorMessage [out] return 값이 false 일 경우. 오류 메시지 저장.
|
||||
bool RecvFileExecuteSyncFromMaster( std::string& strSaveFileName, std::string& strErrorMessage );
|
||||
|
||||
|
||||
// Packet 의 Header 정보를 수신하여 각 정보를 전달받은 참조변수로 반환.
|
||||
// @param bRequest [out] Request 요청인지 여부
|
||||
// @param bFromClient [out] Client 로 부터 전달된 Command 인지 여부
|
||||
// @param command [out] Command 정보
|
||||
// @return 1 : Data 수신 성공시
|
||||
// 0 : Timeout 발생시
|
||||
// -1 : 접속 종료시
|
||||
int GetHeaderInfo( bool& bRequest, bool& bFromClient, char& command );
|
||||
|
||||
// Packet 의 Header 정보 중 현재 전달받은 Header 의 Result 값을 반환
|
||||
// @param result [out] result 4 Byte 부분의 값을 저장하기 위한 참조변수
|
||||
// @return result 4 Byte 부분 중 첫번째 Byte 값을 반환.
|
||||
char GetHeaderResult( void );
|
||||
void GetHeaderResult( std::vector<char>& result );
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리
|
||||
void PrintHeaderToLog( void );
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 변수
|
||||
struct RcSyncdPacketHeader m_packetHeader;
|
||||
|
||||
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_nPacketHeaderLen;
|
||||
|
||||
// Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_nPacketDataLen;
|
||||
|
||||
// Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
|
||||
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Packet Header 부분의 수신 처리를 위한 함수.
|
||||
// @param timeout [in] 대기시간.
|
||||
// @retrun
|
||||
// 1 : PACKET_HEADER_RECEIVE_SUCCESS : 성공시
|
||||
// 0 : PACKET_HEADER_RECEIVE_TIMEOUT : Timeout 발생시
|
||||
// -1 : PACKET_HEADER_RECEIVE_SOCK_CLOSED : socket 종료된 경우
|
||||
// -2 : PACKET_HEADER_RECEIVE_INVALID_PROTOCOL : 잘못된 Packet 형식인 경우
|
||||
// -3 : PACKET_HEADER_RECEIVE_READ_ERROR : 기타 오류
|
||||
int GetPacketHeader(int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @param value [out] 읽은 데이터를 저장할 string 변수
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int& size, std::string& value );
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int size );
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
|
||||
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
|
||||
unsigned long long GetDataToUInt64( BYTE * pValue );
|
||||
|
||||
// 전달받은 Directory 정보를 확인하여 존재하지 않을 경우 생성처리.
|
||||
bool MakeDirectory( const std::string& szFullPath );
|
||||
|
||||
// Socket 으로 부터 수신받은 데이터를 파일에 Write 처리한다.
|
||||
// 만약 File Write 처리시 오류가 발생하는 경우 Socket Data 의 정상적인 처리를 위해
|
||||
// Socket 데이터 수신만 처리하고 오류를 반환한다.
|
||||
// @returnFile Write 가 오류 없이 정상적으로 처리된 경우 true, 오류발생시 false 및 오류메시지 반환
|
||||
bool ReceiveToFile( FILE * pFile, unsigned long long nFileSize, std::string& errorMessage );
|
||||
|
||||
// Packet 정보 중 String 정보를 전송하기 위한 함수.
|
||||
bool SendString( const std::string& strData );
|
||||
|
||||
};
|
||||
|
||||
#endif /* __PROCESS_SOCKET_CONTROL_H__ */
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
#include "ProcessStatus.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessRename.h"
|
||||
|
||||
// Process 정보 update 주기 (sec)
|
||||
#define PROCESS_STATUS_UPDATE_TIME 3
|
||||
|
||||
|
||||
// 생성자
|
||||
CProcessStatus::CProcessStatus()
|
||||
{
|
||||
m_threadHandle = 0;
|
||||
|
||||
m_nCurrentClientCount = 0;
|
||||
m_nCurrentMasterCount = 0;
|
||||
m_nCurrentSlaveCount = 0;
|
||||
m_nCurrentSyncCount = 0;
|
||||
|
||||
// Lock 초기화
|
||||
pthread_mutex_init( &m_mxClientThread, NULL );
|
||||
pthread_mutex_init( &m_mxModeMaster, NULL );
|
||||
pthread_mutex_init( &m_mxModeSlave, NULL );
|
||||
pthread_mutex_init( &m_mxModeSync, NULL );
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CProcessStatus::~CProcessStatus()
|
||||
{
|
||||
// Thread 동작 정지 처리
|
||||
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로
|
||||
// 업무 Flow 수정시 주의할 것
|
||||
if( m_threadHandle != 0 )
|
||||
pthread_cancel( m_threadHandle );
|
||||
|
||||
pthread_mutex_destroy( &m_mxClientThread );
|
||||
pthread_mutex_destroy( &m_mxModeMaster );
|
||||
pthread_mutex_destroy( &m_mxModeSlave );
|
||||
pthread_mutex_destroy( &m_mxModeSync );
|
||||
}
|
||||
|
||||
// thread를 생성하여 관련 작업을 수행.
|
||||
bool CProcessStatus::Start()
|
||||
{
|
||||
int nRet = ::pthread_create( &m_threadHandle, NULL, CProcessStatus::threadFunc, this );
|
||||
if( nRet != 0 )
|
||||
{
|
||||
// Thread 생성 실패시
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* CProcessStatus::threadFunc( void* arg )
|
||||
{
|
||||
CProcessStatus* pObject = reinterpret_cast<CProcessStatus *>( arg );
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
pObject->Execute();
|
||||
|
||||
sleep( PROCESS_STATUS_UPDATE_TIME );
|
||||
}
|
||||
|
||||
// Thread 종료시 m_threadHandle 값을 초기화 처리.
|
||||
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
|
||||
pObject->m_threadHandle = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// 현재 프로세스 표시 정보 업데이트
|
||||
void CProcessStatus::Execute( void )
|
||||
{
|
||||
// C: client count
|
||||
// M: master job count
|
||||
// S: slave job count
|
||||
// Y: sync job count
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
setproctitle("[C%d M%d S%d Y%d]",
|
||||
m_nCurrentClientCount,
|
||||
m_nCurrentMasterCount,
|
||||
m_nCurrentSlaveCount,
|
||||
m_nCurrentSyncCount );
|
||||
|
||||
#else
|
||||
char szTemp[100] = {0};
|
||||
sprintf(szTemp, "%s: Worker [C%d M%d S%d Y%d]",
|
||||
PROG_NAME,
|
||||
m_nCurrentClientCount,
|
||||
m_nCurrentMasterCount,
|
||||
m_nCurrentSlaveCount,
|
||||
m_nCurrentSyncCount );
|
||||
|
||||
set_ps_display(szTemp, false);
|
||||
|
||||
#endif
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
|
||||
// Client 수를 1 증가 처리
|
||||
void CProcessStatus::PlusClientCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxClientThread );
|
||||
++m_nCurrentClientCount;
|
||||
pthread_mutex_unlock( &m_mxClientThread );
|
||||
}
|
||||
|
||||
// Client 수를 1 감소 처리
|
||||
// - 정확히 동작하는지 확인을 위해 일부로 (-) 값 보정 처리 안함.
|
||||
void CProcessStatus::MinusClientCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxClientThread );
|
||||
--m_nCurrentClientCount;
|
||||
pthread_mutex_unlock( &m_mxClientThread );
|
||||
}
|
||||
|
||||
// Master Mode Job 을 1 증가 처리
|
||||
void CProcessStatus::PlusMasterModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeMaster );
|
||||
++m_nCurrentMasterCount;
|
||||
pthread_mutex_unlock( &m_mxModeMaster );
|
||||
}
|
||||
|
||||
// Master Mode Job 을 1 감소 처리
|
||||
// - 정확히 동작하는지 확인을 위해 일부로 (-) 값 보정 처리 안함.
|
||||
void CProcessStatus::MinusMasterModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeMaster );
|
||||
--m_nCurrentMasterCount;
|
||||
pthread_mutex_unlock( &m_mxModeMaster );
|
||||
}
|
||||
|
||||
// Slave Mode Job 을 1 증가 처리
|
||||
void CProcessStatus::PlusSlaveModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeSlave );
|
||||
++m_nCurrentSlaveCount;
|
||||
pthread_mutex_unlock( &m_mxModeSlave );
|
||||
}
|
||||
|
||||
// Slave Mode Job 을 1 감소 처리
|
||||
// - 정확히 동작하는지 확인을 위해 일부로 (-) 값 보정 처리 안함.
|
||||
void CProcessStatus::MinusSlaveModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeSlave );
|
||||
--m_nCurrentSlaveCount;
|
||||
pthread_mutex_unlock( &m_mxModeSlave );
|
||||
}
|
||||
|
||||
// Sync Mode Job 을 1 증가 처리
|
||||
void CProcessStatus::PlusSyncModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeSync );
|
||||
++m_nCurrentSyncCount;
|
||||
pthread_mutex_unlock( &m_mxModeSync );
|
||||
}
|
||||
|
||||
// Sync Mode Job 을 1 감소 처리
|
||||
// - 정확히 동작하는지 확인을 위해 일부로 (-) 값 보정 처리 안함.
|
||||
void CProcessStatus::MinusSyncModeCount()
|
||||
{
|
||||
pthread_mutex_lock( &m_mxModeSync );
|
||||
--m_nCurrentSyncCount;
|
||||
pthread_mutex_unlock( &m_mxModeSync );
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/***************************************************************************
|
||||
Process 상태 정보 저장 및 console 출력 처리 class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/12
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : storage dev team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __PROCESS_STATUS_H__
|
||||
#define __PROCESS_STATUS_H__
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
// CProcessStatus class
|
||||
// - 프로세스 의 Client 수, 각 Mode 별 수행 수 정보를 저장
|
||||
// - 해당 정보를 console 상에 표시하는 역활을 수행한다.
|
||||
class CProcessStatus
|
||||
{
|
||||
public :
|
||||
|
||||
// 생성자
|
||||
CProcessStatus();
|
||||
|
||||
// 소멸자
|
||||
~CProcessStatus();
|
||||
|
||||
// thread를 생성하여 프로세스 출력 상태 갱신 작업을 수행.
|
||||
bool Start();
|
||||
|
||||
|
||||
// Client 수를 1 증가 처리
|
||||
void PlusClientCount(void);
|
||||
// Client 수를 1 감소 처리
|
||||
void MinusClientCount(void);
|
||||
|
||||
// Master Mode Job 을 1 증가 처리
|
||||
void PlusMasterModeCount( void );
|
||||
// Master Mode Job 을 1 감소 처리
|
||||
void MinusMasterModeCount( void );
|
||||
|
||||
// Slave Mode Job 을 1 증가 처리
|
||||
void PlusSlaveModeCount( void );
|
||||
// Slave Mode Job 을 1 감소 처리
|
||||
void MinusSlaveModeCount( void );
|
||||
|
||||
// Sync Mode Job 을 1 증가 처리
|
||||
void PlusSyncModeCount( void );
|
||||
// Sync Mode Job 을 1 감소 처리
|
||||
void MinusSyncModeCount( void );
|
||||
|
||||
|
||||
private :
|
||||
|
||||
// 스레드 함수
|
||||
static void* threadFunc( void* arg );
|
||||
|
||||
// 현재 프로세스 표시 정보 업데이트
|
||||
void Execute( void );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 쓰레드 핸들
|
||||
pthread_t m_threadHandle;
|
||||
|
||||
|
||||
// Lock 처리 관련
|
||||
pthread_mutex_t m_mxClientThread;
|
||||
pthread_mutex_t m_mxModeMaster;
|
||||
pthread_mutex_t m_mxModeSlave;
|
||||
pthread_mutex_t m_mxModeSync;
|
||||
|
||||
|
||||
////// 프로세스 title 로 모니터 대상 정보 /////////////
|
||||
|
||||
// 접속 Client 수
|
||||
int m_nCurrentClientCount;
|
||||
|
||||
// Master Mode job 수
|
||||
int m_nCurrentMasterCount;
|
||||
|
||||
// Slave Mode job 수
|
||||
int m_nCurrentSlaveCount;
|
||||
|
||||
// Sync Mode job 수
|
||||
int m_nCurrentSyncCount;
|
||||
|
||||
};
|
||||
|
||||
#endif //__PROCESS_STATUS_H__
|
||||
@@ -0,0 +1,320 @@
|
||||
#include "RcSyncdClientSocket.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
// 생성자.
|
||||
CRcSyncdClientSocket::CRcSyncdClientSocket()
|
||||
: CBaseSocket( SOCKET_NOT_VALID )
|
||||
, m_nPacketHeaderLen ( sizeof(m_packetHeader))
|
||||
, m_nPacketDataLen( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CRcSyncdClientSocket::~CRcSyncdClientSocket()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
// 전달받은 Target 으로 Socket 접속을 수행
|
||||
// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
// @param nPort [in] 접속 Port
|
||||
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool CRcSyncdClientSocket::ConnectTarget( const std::string& szTarget, int nPort )
|
||||
{
|
||||
return Connect( szTarget, nPort );
|
||||
}
|
||||
|
||||
// rc_syncd 로 sync 명령 전달.
|
||||
// - CReqMasterData class 멤버변수 수정시 본 함수 수정 필요함.
|
||||
bool CRcSyncdClientSocket::SendSyncRequest( CReqMasterData& request )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 정보 요청을 위한 Packet Header 생성.
|
||||
struct RcSyncdPacketHeader stHeader;
|
||||
memset( &stHeader, 0x00, sizeof( struct RcSyncdPacketHeader ) );
|
||||
|
||||
stHeader.stx = HEADER_STX_CODE;
|
||||
stHeader.type = HEADER_TYPE_REQUEST;
|
||||
stHeader.command[0] = CLIENT_COMMAND_SYNC;
|
||||
|
||||
// Data 부분의 길이를 계산한다.
|
||||
unsigned int nTemp = 0;
|
||||
nTemp = 4; // sync_type
|
||||
nTemp += ( 4 + request.start_time.size() ); // start_time
|
||||
nTemp += ( 4 + request.end_time.size() ); // end_time
|
||||
nTemp += ( 4 + request.one_service.size() ); // one_service
|
||||
|
||||
stHeader.data_length = htonl( nTemp );
|
||||
|
||||
// Packet Header 정보 전송
|
||||
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
|
||||
{
|
||||
LOG( LERR, "request[CLIENT_COMMAND_SYNC] send fail to rc_syncd. " );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Data 부분 전송
|
||||
// 1. sync_type
|
||||
nTemp = htonl( request.sync_type );
|
||||
WriteN( &nTemp, 4 );
|
||||
// 2. start_time
|
||||
SendString( request.start_time );
|
||||
// 3. end_time
|
||||
SendString( request.end_time );
|
||||
// 4. one_service
|
||||
SendString( request.one_service );
|
||||
}
|
||||
|
||||
LOG( LDBG, "request[CLIENT_COMMAND_SYNC] send OK. type[%d] time[%s]~[%s] svc[%s]"
|
||||
, request.sync_type, request.start_time.c_str(), request.end_time.c_str()
|
||||
, (request.one_service.empty() == true ? "ALL" : request.one_service.c_str()) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// rc_syncd 로 부터 sync 요청에 대한 결과 수신.
|
||||
int CRcSyncdClientSocket::GetSyncResult( int nTimeout, bool& bSuccess, std::string& strMessage )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return -1;
|
||||
|
||||
int nRead;
|
||||
bool isAlivePacket;
|
||||
|
||||
do
|
||||
{
|
||||
isAlivePacket = false;
|
||||
|
||||
// Socket 으로 부터 Packet Header 부분 수신.
|
||||
// 수신된 정보는 멤버변수에 저장처리.
|
||||
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
|
||||
|
||||
// nRead 0: Socket Closed
|
||||
// -1: error
|
||||
// -2: Timeout 이므로
|
||||
if( nRead == -2 )
|
||||
return 0; // Timeout 반환.
|
||||
else if( nRead == 0 || nRead == -1 )
|
||||
return -1; // Socket Close 또는 오류 발생시
|
||||
|
||||
// STX code 검사.
|
||||
if( m_packetHeader.stx != HEADER_STX_CODE )
|
||||
{
|
||||
LOG( LERR, "Not valid stx code." );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Data Length 부분 값을 멤버 변수에 저장처리.
|
||||
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
|
||||
|
||||
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
|
||||
if( m_packetHeader.type == HEADER_TYPE_REQUEST
|
||||
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
|
||||
&& m_nPacketDataLen == 0 )
|
||||
{
|
||||
isAlivePacket = true;
|
||||
}
|
||||
|
||||
} while( isAlivePacket == true );
|
||||
|
||||
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 응답패킷인지 검사.
|
||||
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|
||||
|| m_packetHeader.command[0] != CLIENT_COMMAND_SYNC )
|
||||
{
|
||||
// 다른 패킷이 들어온 경우
|
||||
|
||||
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
|
||||
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
|
||||
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
|
||||
GetPacketData( m_nPacketDataLen );
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Sync 요청에 대한 응답패킷인 경우.
|
||||
|
||||
// 1. 성공, 실패 여부 판단.
|
||||
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
|
||||
bSuccess = false;
|
||||
else
|
||||
bSuccess = true;
|
||||
|
||||
// 2. Data 부분에 대한 처리
|
||||
// - Message 부분이 존재할 수 있으므로..
|
||||
// 성공/실패 구분 없이 모두 Data 부분 수신 처리한다.
|
||||
if( m_nPacketDataLen > 0 )
|
||||
{
|
||||
if( GetPacketData( m_nPacketDataLen, strMessage ) == false )
|
||||
{
|
||||
LOG( LERR, "data body receive failed." );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 자동 무시처리됨.
|
||||
// @return 전송 성공시 true, 실패시 false 반환.
|
||||
bool CRcSyncdClientSocket::SendAliveCheck()
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 정보 요청을 위한 Packet Header 생성.
|
||||
struct RcSyncdPacketHeader stHeader;
|
||||
memset( &stHeader, 0x00, sizeof( struct RcSyncdPacketHeader ) );
|
||||
|
||||
stHeader.stx = HEADER_STX_CODE;
|
||||
stHeader.type = HEADER_TYPE_REQUEST;
|
||||
stHeader.command[0] = COMMON_ALIVE_CHECK;
|
||||
|
||||
// Packet Header 정보 전송
|
||||
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리
|
||||
void CRcSyncdClientSocket::PrintHeaderToLog()
|
||||
{
|
||||
_LOG( LINF, "------------------------------------" );
|
||||
_LOG( LINF, "stx [%02x]", m_packetHeader.stx );
|
||||
_LOG( LINF, "type [%02x]", m_packetHeader.type );
|
||||
_LOG( LINF, "command [%02x][%02x][%02x][%02x]", m_packetHeader.command[0], m_packetHeader.command[1], m_packetHeader.command[2], m_packetHeader.command[3] );
|
||||
_LOG( LINF, "result [%02x][%02x][%02x][%02x]", m_packetHeader.result[0], m_packetHeader.result[1], m_packetHeader.result[2], m_packetHeader.result[3] );
|
||||
_LOG( LINF, "data_length [%u]", m_nPacketDataLen );
|
||||
_LOG( LINF, "extend_code [%02x][%02x]", m_packetHeader.extend_code[0], m_packetHeader.extend_code[1] );
|
||||
_LOG( LINF, "------------------------------------" );
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Packet 정보 중 String 정보를 전송하기 위한 함수.
|
||||
bool CRcSyncdClientSocket::SendString( const std::string& strData )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return false;
|
||||
|
||||
// 크기값을 저장하기 위한 임시 변수.
|
||||
unsigned int nSize = 0;
|
||||
|
||||
// String Data 전송
|
||||
nSize = htonl( strData.size() );
|
||||
WriteN( &nSize, 4 );
|
||||
if( strData.size() > 0 )
|
||||
WriteN( strData.c_str(), strData.size() );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @param value [out] 읽은 데이터를 저장할 string 변수
|
||||
// @return On success return true, otherwise return false.
|
||||
bool CRcSyncdClientSocket::GetPacketData( unsigned int& size, std::string& value )
|
||||
{
|
||||
// 1. 수신할 크기가 임시버퍼보다 큰 경우 새로운 버퍼를 생성한다.
|
||||
BYTE * pBuffer = NULL;
|
||||
bool bNewBufferCreated = false;
|
||||
if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
|
||||
{
|
||||
pBuffer = new BYTE[size]; // 신규 메모리 할당.
|
||||
bNewBufferCreated = true;
|
||||
}
|
||||
else
|
||||
pBuffer = m_tempBuffer;
|
||||
|
||||
// 2. 데이터 수신 처리.
|
||||
int nRead = ReadNTimeout( pBuffer, size );
|
||||
|
||||
// 오류 발생시
|
||||
if( nRead <= 0 )
|
||||
{
|
||||
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
|
||||
if( bNewBufferCreated == true )
|
||||
delete[] pBuffer;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. 수신 데이터 저장 처리 - 기존 데이터 뒤에 붙여 준다=> 이게 사용하기 편함.
|
||||
value.append( (char *)pBuffer, size );
|
||||
|
||||
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
|
||||
if( bNewBufferCreated == true )
|
||||
delete[] pBuffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @return On success return true, otherwise return false.
|
||||
bool CRcSyncdClientSocket::GetPacketData( unsigned int size )
|
||||
{
|
||||
// 1. 수신할 크기가 임시버퍼보다 큰 경우 오류 반환.
|
||||
if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
|
||||
return false;
|
||||
|
||||
// 2. 데이터 수신 처리.
|
||||
int nRead = ReadNTimeout( m_tempBuffer, size );
|
||||
|
||||
// 오류 발생시
|
||||
if( nRead <= 0 )
|
||||
return false;
|
||||
|
||||
// 3. 정상인 경우는 ReadNTimeout 함수가 무조건 요청 크기만큼 read 처리하므로 정상수신임.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 전달받은 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
|
||||
unsigned int CRcSyncdClientSocket::GetDataToUInt( BYTE * pValue, bool bConvertEndian )
|
||||
{
|
||||
BYTE tempBuffer[4];
|
||||
unsigned int result;
|
||||
|
||||
memcpy(tempBuffer, pValue, 4);
|
||||
unsigned int * pInt = (unsigned int *)tempBuffer;
|
||||
|
||||
// Endian 변환처리.
|
||||
if( bConvertEndian == true )
|
||||
{
|
||||
result = ntohl( *pInt );
|
||||
}
|
||||
else
|
||||
result = *pInt;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
|
||||
unsigned long long CRcSyncdClientSocket::GetDataToUInt64( BYTE * pValue )
|
||||
{
|
||||
unsigned long long * pResult;
|
||||
BYTE tempBuffer[8];
|
||||
memcpy(tempBuffer, pValue, 8);
|
||||
|
||||
pResult = (unsigned long long *)tempBuffer;
|
||||
|
||||
return *pResult;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/***************************************************************************
|
||||
client 에서 rc_syncd 와의 통신을 수행하기 위한 class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/15
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __RC_SYNCD_CLIENT_SOCKET_H__
|
||||
#define __RC_SYNCD_CLIENT_SOCKET_H__
|
||||
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "RcSyncdProtocol.h"
|
||||
#include "RcSyncdRequestData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
///< BYTE 타입 정의
|
||||
#ifndef _BYTE_DEFINED
|
||||
#define _BYTE_DEFINED
|
||||
typedef unsigned char BYTE;
|
||||
#endif // _BYTE_DEFINED
|
||||
|
||||
|
||||
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // Socket 관련 data 송수신시 사용할 임시버퍼 크기.
|
||||
|
||||
|
||||
// CRcSyncdClientSocket
|
||||
// 내부 또는 외부 모듈에서 rc_syncd 와 통신 수행시...
|
||||
// 함수 수준의 단순 Interface 지원 목적을 위한 통신 관련 처리 class
|
||||
class CRcSyncdClientSocket : public CBaseSocket
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성자
|
||||
CRcSyncdClientSocket();
|
||||
|
||||
// 소멸자
|
||||
~CRcSyncdClientSocket();
|
||||
|
||||
|
||||
// 전달받은 Target 으로 Socket 접속을 수행
|
||||
// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
// @param nPort [in] 접속 Port
|
||||
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool ConnectTarget( const std::string& szTarget, int nPort );
|
||||
|
||||
|
||||
// rc_syncd 로 sync 명령 전달.
|
||||
// - CReqMasterData class 멤버변수 수정시 본 함수 수정 필요함.
|
||||
// @param request [in] 요청 정보 저장 객체
|
||||
// @return true 요청 성공시
|
||||
// fasle 유효하지 않은 인자값 또는 전송 실패시
|
||||
bool SendSyncRequest( CReqMasterData& request );
|
||||
|
||||
|
||||
// rc_syncd 로 부터 sync 요청에 대한 결과 수신.
|
||||
// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )
|
||||
// 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
// @param bSuccess [out] 성공 여부
|
||||
// @param strMessage [out] rc_syncd 로부터 처리 관련 수신된 메시지
|
||||
// @return
|
||||
// -1 : rc_syncd 와 통신이 끊어진 경우.
|
||||
// 0 : rc_syncd 로 부터 응답을 아직 수신하지 못한 경우..
|
||||
// - 함수 blocking 방지 목적
|
||||
// => AliveCheck 등의 작업 후 다시 응답 대기하면 된다.
|
||||
// 1 : Sync 요청에 대한 응답을 수신한 경우
|
||||
// 2 : Sync 요청에 대한 응답이 아닌 경우..
|
||||
// => 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int GetSyncResult( int nTimeout, bool& bSuccess, std::string& strMessage );
|
||||
|
||||
|
||||
// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 자동 무시처리됨.
|
||||
// @return 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendAliveCheck( void );
|
||||
|
||||
// Packet Header 정보를 Log 파일에 Logging 처리
|
||||
// - 통신 오류 발생시 로깅을 통한 디버깅 지원 목적
|
||||
void PrintHeaderToLog( void );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Packet Header 변수
|
||||
struct RcSyncdPacketHeader m_packetHeader;
|
||||
|
||||
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_nPacketHeaderLen;
|
||||
|
||||
// Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_nPacketDataLen;
|
||||
|
||||
// Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
|
||||
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
// Packet 정보 중 String 정보를 전송하기 위한 함수.
|
||||
bool SendString( const std::string& strData );
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @param value [out] 읽은 데이터를 저장할 string 변수
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int& size, std::string& value );
|
||||
|
||||
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
|
||||
// @param size [in] read 할 데이터 크기
|
||||
// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int size );
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
|
||||
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
|
||||
|
||||
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
|
||||
unsigned long long GetDataToUInt64( BYTE * pValue );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* __RC_SYNCD_CLIENT_SOCKET_H__ */
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
rc_syncd 통신 관련 protocol header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/04
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef __RC_SYNCD_PROTOCOL_H__
|
||||
#define __RC_SYNCD_PROTOCOL_H__
|
||||
|
||||
|
||||
// rc_syncd 에서 사용할 통신 Header 구조체
|
||||
// - 계산상 크기는 16Byte 이지만...
|
||||
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
|
||||
struct RcSyncdPacketHeader {
|
||||
|
||||
char stx; // Packet 유효성 관리 코드
|
||||
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
|
||||
char command[4]; // Command Code ( 4 Byte) : 0th client-rc_syncd, 1th rc_syncd - rc_syncd 간 사용.
|
||||
char result[4]; // Result Code ( 4 Byte )
|
||||
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
|
||||
char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
|
||||
};
|
||||
|
||||
// Packet Header stx 코드
|
||||
#define HEADER_STX_CODE 0x03
|
||||
|
||||
// Packet Header type 구분코드
|
||||
#define HEADER_TYPE_REQUEST 0x00
|
||||
#define HEADER_TYPE_RESPONSE 0x01
|
||||
|
||||
|
||||
// Packet command 공통.
|
||||
#define COMMON_ALIVE_CHECK 0x7F
|
||||
|
||||
// Packet command
|
||||
// client <-> rc_syncd 통신 (command 0th byte 만 사용)
|
||||
|
||||
#define NOT_CLIENT_COMMAND 0x00 // Client 에서 전송한 요청이 아닌 경우.
|
||||
#define CLIENT_COMMAND_SYNC 0x01 // Client 에서 동기화 수행 요청
|
||||
|
||||
// Packet command
|
||||
// rc_syncd <-> rc_syncd 간의 내부 통신 (command 1st byte 만 사용)
|
||||
|
||||
#define PROCESS_CONTENT_LIST 0x01 // Content 정보 목록 요청 => RCDB 에서 Content 정보 추출 후 전달
|
||||
#define PROCESS_CONTENT_SYNC 0x02 // 동기화 수행 요청 (동기화 대상 목록 전달) => 동기화 수행 후 결과 전달.
|
||||
|
||||
|
||||
// Packet Result
|
||||
// => type이 Response 인 경우에만 세팅됨.( 0th Byte 만 사용시 )
|
||||
#define HEADER_RESULT_SUCCESS 0x00
|
||||
#define HEADER_RESULT_ERROR 0x01
|
||||
|
||||
|
||||
// 기타 정보
|
||||
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
|
||||
|
||||
|
||||
#endif /* __RC_SYNCD_PROTOCOL_H__ */
|
||||
@@ -0,0 +1,110 @@
|
||||
#include "RcSyncdRequest.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
#include "RcSyncdClientSocket.h" // rc_syncd 와 통신을 처리할 client socket 객체 생성 및 접속
|
||||
#define RC_SYNCD_HOST "127.0.0.1" // rc_syncd host
|
||||
|
||||
CRcSyncdRequest::CRcSyncdRequest()
|
||||
{
|
||||
}
|
||||
|
||||
CRcSyncdRequest::~CRcSyncdRequest()
|
||||
{
|
||||
}
|
||||
|
||||
void CRcSyncdRequest::SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime)
|
||||
{
|
||||
SendSyncRequest(nSyncType, strStartTime, strEndTime, "");
|
||||
}
|
||||
|
||||
void CRcSyncdRequest::SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime, const std::string& strService)
|
||||
{
|
||||
bool bResultSuccess = false; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
|
||||
std::string strMessage; // 수신 메시지 저장 변수.
|
||||
int nResult = 0;
|
||||
int nTimeout = 5; // 5sec에 한번씩 Alive Check하기 위함
|
||||
|
||||
// 요청 데이타 생성
|
||||
CReqMasterData request;
|
||||
request.sync_type = (SYNC_TYPE::SYNC_TYPE)nSyncType;
|
||||
request.start_time = strStartTime;
|
||||
request.end_time = strEndTime;
|
||||
request.one_service = strService;
|
||||
|
||||
// local rc_syncd와 통신을 처리할 client socket 객체 생성 및 접속
|
||||
CRcSyncdClientSocket client;
|
||||
if( client.ConnectTarget( RC_SYNCD_HOST, CServiceConfig::GetInstance()->GetOperationPort() ) == false )
|
||||
{
|
||||
// local rc_syncd 으로 접속 실패시
|
||||
_LOG( LERR, "rc_syncd connect fail. [%s][%d]", RC_SYNCD_HOST, CServiceConfig::GetInstance()->GetOperationPort());
|
||||
return ;
|
||||
}
|
||||
|
||||
// rc_syncd로 sync 요청 전달
|
||||
if( client.SendSyncRequest( request ) == false )
|
||||
{
|
||||
// 전송 실패시
|
||||
_LOG( LERR, "Sync request send fail");
|
||||
return ;
|
||||
}
|
||||
|
||||
// 루프를 돌면서 요청에 대한 응답을 대기
|
||||
while(1)
|
||||
{
|
||||
// nTimeout 에 지정된 시간동안 응답대기
|
||||
nResult = client.GetSyncResult( nTimeout, bResultSuccess, strMessage);
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
|
||||
// 해당 내역 로깅 및 루프 종료
|
||||
_LOG( LERR, "Response wait fail by socket" );
|
||||
break;
|
||||
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Alive Check 패킷 한번 쏘고 다시 Loop 로
|
||||
|
||||
if( client.SendAliveCheck() == false )
|
||||
{
|
||||
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
|
||||
_LOG( LERR, "Response wait fail by socket2");
|
||||
break;
|
||||
}
|
||||
LOG( LDBG, "Response wait");
|
||||
// 정상적인 경우 다시 응답대기.
|
||||
continue;
|
||||
}
|
||||
else if( nResult == 1 )
|
||||
{
|
||||
// 요청에 대한 처리결과 정보가 수신된 경우.
|
||||
// 해당 정보 로깅처리.
|
||||
|
||||
if( bResultSuccess == true )
|
||||
{
|
||||
// 요청에 대한 처리가 정상적으로 처리된 경우
|
||||
_LOG( LINF, "Sync result SUCCESS [%s]", strMessage.c_str() );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 오류 발생시
|
||||
_LOG( LINF, "Sync result ERROR [%s]", strMessage.c_str() );
|
||||
|
||||
}
|
||||
|
||||
break; // 응답을 받았으니 응답 대기 루프 종료
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replication 요청에 대한 응답패킷이 아닌 경우.
|
||||
// 해당 패킷은 무시하고 다시 Loop 로
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
client.Close();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/****************************************************************************
|
||||
Synchronization Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/17
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __RCSYNCDREQUEST_H__
|
||||
#define __RCSYNCDREQUEST_H__
|
||||
|
||||
#include "RcSyncdRequestData.h"
|
||||
|
||||
class CRcSyncdRequest
|
||||
{
|
||||
public:
|
||||
CRcSyncdRequest();
|
||||
~CRcSyncdRequest();
|
||||
|
||||
void SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime);
|
||||
void SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime, const std::string& strService);
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif /* __RCSYNCDREQUEST_H__ */
|
||||
@@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
rc_syncd Request Data Header ( RcSyncdRequestData.h )
|
||||
- used : rc_cmove, rc_syncd(Scheduler)
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __RC_SYNCD_REQUEST_DATA_H__
|
||||
#define __RC_SYNCD_REQUEST_DATA_H__
|
||||
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace SYNC_TYPE
|
||||
{
|
||||
|
||||
enum SYNC_TYPE
|
||||
{
|
||||
NORMAL = 0, // 동기화 요청(O), 모든 데이터 (복제, 캐쉬 제외)
|
||||
NORMA_N_ONLY = 1, // 동기화 요청(O), deleted_yn = N
|
||||
CHK_ONLY = 3, // 동기화 요청(X), 모든 데이터 (복제, 캐쉬 제외)
|
||||
CHK_ONLY_N_ONLY = 4 // 동기화 요청(X), deleted_yn = N
|
||||
};
|
||||
}
|
||||
|
||||
// Requeset Data
|
||||
/// base Data
|
||||
class CReqServiceData
|
||||
{
|
||||
public:
|
||||
CReqServiceData(){};
|
||||
~CReqServiceData(){};
|
||||
|
||||
public:
|
||||
SYNC_TYPE::SYNC_TYPE sync_type;
|
||||
|
||||
string start_time;
|
||||
string end_time;
|
||||
};
|
||||
|
||||
// admin(scheduler) => rc_syncd(Master)
|
||||
class CReqMasterData : public CReqServiceData
|
||||
{
|
||||
public:
|
||||
CReqMasterData(){};
|
||||
~CReqMasterData(){};
|
||||
|
||||
public:
|
||||
// one_service 값이 없을 수도 있음
|
||||
// Scheduler : 해당 정보를 보내지 않음(RCDB 작업 회피를 위함)
|
||||
// 운영자(rc_cmove) : 특정 고객만 수행 시킬 수 있으므로 해당 값은 유동적임
|
||||
string one_service;
|
||||
|
||||
};
|
||||
|
||||
// rc_syncd(Master) => rc_syncd(slave)
|
||||
class CReqSlaveData : public CReqServiceData
|
||||
{
|
||||
public:
|
||||
CReqSlaveData(){};
|
||||
~CReqSlaveData(){};
|
||||
|
||||
public:
|
||||
string master;
|
||||
string slave;
|
||||
};
|
||||
|
||||
// rc_syncd(Master) => rc_syncd(slave)
|
||||
class CReqSyncData : public CReqServiceData
|
||||
{
|
||||
public:
|
||||
CReqSyncData(){};
|
||||
~CReqSyncData(){};
|
||||
|
||||
public:
|
||||
string master;
|
||||
string slave;
|
||||
};
|
||||
|
||||
#endif /* __RC_SYNCD_REQUEST_DATA_H__ */
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "RcdbInfo.h"
|
||||
#include "ServiceConfig.h"
|
||||
|
||||
// 생성자..
|
||||
CRcdbInfo::CRcdbInfo()
|
||||
{
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CRcdbInfo::~CRcdbInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// CServiceConfig Class 에 저장된 RCDB 접속 정보를 가져와 멤버 변수에 저장한다.
|
||||
void CRcdbInfo::Load()
|
||||
{
|
||||
// CServiceConfig Class 에서 기본적인 설정값에 대해 검사를 수행하므로...
|
||||
// 본 Class 에서 다시 유효성 검사를 할 필요는 없다.. ( 어차피 유효성 검사 방법이 동일하므로.. )
|
||||
|
||||
// RCDB IP
|
||||
m_strRcdbIp = CServiceConfig::GetInstance()->GetRcdbIp();
|
||||
|
||||
// RCDB Port
|
||||
m_nRcdbPort = CServiceConfig::GetInstance()->GetRcdbPort();
|
||||
|
||||
// RCDB DB Name
|
||||
m_strRcdbName = CServiceConfig::GetInstance()->GetRcdbName();
|
||||
|
||||
// RCDB 접근 계정
|
||||
m_strRcdbAcct = CServiceConfig::GetInstance()->GetRcdbAcct();
|
||||
|
||||
// RCDB 접근 Password.
|
||||
m_strRcdbAcctPw = CServiceConfig::GetInstance()->GetRcdbAcctPw();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
RCDB 접속 정보 저장 처리 Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/11/13
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Dev 1 Team
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __RCDB_INFO_H__
|
||||
#define __RCDB_INFO_H__
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
/// @brief CRcdbInfo
|
||||
/// 본 클래스는 conf 파일에 저장된 RCDB 접속 관련 정보를 저장하기 위한 공용 Class...
|
||||
/// 본 클래스를 사용하지 않고... CServiceConfig class 의 Get 함수를 이용하여 RCDB 접속 정보를 처리해도 된다..
|
||||
/// 하지만... RCDB 접속 처리 Class 함수의 string type 변수 사용으로 인해... 여러 모듈에서 반복적인 동일 코드 처리 작업을 수행해야 하므로...
|
||||
/// 본 Class 를 통해 코드를 단순화 시킬 목적으로 사용한다.
|
||||
class CRcdbInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// 생성 및 소멸자.
|
||||
CRcdbInfo();
|
||||
~CRcdbInfo();
|
||||
|
||||
// CServiceConfig class 에 저장된 RCDB 접속 정보를 멤버 변수에 저장처리한다.
|
||||
void Load( void );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 멤버 변수들은 DB 접속을 처리하는 객체에서 직접 Access 해서 사용할 수 있도록 public 으로 구성. ( 편의성 제공 목적)
|
||||
std::string m_strRcdbIp; // RCDB IP
|
||||
unsigned int m_nRcdbPort; // RCDB Port
|
||||
std::string m_strRcdbName; // RCDB DB Name
|
||||
std::string m_strRcdbAcct; // RCDB 접근 계정
|
||||
std::string m_strRcdbAcctPw; // RCDB 접근 Password.
|
||||
|
||||
};
|
||||
|
||||
#endif /* __RCDB_INFO_H__ */
|
||||
@@ -0,0 +1,351 @@
|
||||
/***************************************************************************
|
||||
Running
|
||||
-----------------------------------------
|
||||
begin : 2011/11/01
|
||||
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 "Running.h"
|
||||
#include "Scheduler.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
#include "Util.h"
|
||||
#include "RcSyncdClientSocket.h" // rc_syncd 와 통신을 처리할 client socket 객체 생성 및 접속
|
||||
#include "RcSyncdRequest.h"
|
||||
|
||||
// runlist
|
||||
CRunlist *CRunlist::m_inst = NULL;
|
||||
|
||||
CRunlist::CRunlist()
|
||||
{
|
||||
pthread_mutex_init(&m_findmutex, NULL);
|
||||
}
|
||||
|
||||
CRunlist::~CRunlist()
|
||||
{
|
||||
pthread_mutex_destroy(&m_findmutex);
|
||||
}
|
||||
|
||||
void CRunlist::init()
|
||||
{
|
||||
if (CRunlist::m_inst == NULL)
|
||||
{
|
||||
CRunlist::m_inst = new CRunlist();
|
||||
}
|
||||
}
|
||||
|
||||
CRunlist* CRunlist::getInstance()
|
||||
{
|
||||
return CRunlist::m_inst;
|
||||
}
|
||||
|
||||
void CRunlist::release()
|
||||
{
|
||||
if (CRunlist::m_inst != NULL)
|
||||
{
|
||||
while(m_inst->m_list.size() > 0 )
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
delete CRunlist::m_inst;
|
||||
CRunlist::m_inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CRunlist::addlist(CRunning *run)
|
||||
{
|
||||
bool r = true;
|
||||
pthread_mutex_lock(&m_findmutex);
|
||||
|
||||
stringstream msg;
|
||||
time_t newstart = 0;
|
||||
time_t newend = 0;
|
||||
|
||||
if( findnewtime(run->getstart(), run->getend(), newstart, newend) == false)
|
||||
{
|
||||
msg << "[running:" << pthread_self() << "] input values used.";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
newstart = run->getstart();
|
||||
newend = run->getend();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "[running:" << pthread_self() << "] changed values used.";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
}
|
||||
|
||||
msg.str("");
|
||||
if( newstart == newend)
|
||||
{
|
||||
r = false;
|
||||
msg << "[running:" << pthread_self() << "]running start and end are the same.";
|
||||
cout << msg.str() << endl;
|
||||
LOG(LWAR, msg.str().c_str());
|
||||
}
|
||||
else if(newstart > newend)
|
||||
{
|
||||
r = false;
|
||||
msg << "[running:" << pthread_self() << "]running error[Start time is greater than the end of time]." << endl;
|
||||
msg << " Start Time : " << time_t2string(run->getstart()) << " => " << time_t2string(run->getstart()) << endl;
|
||||
msg << " End Time : " << time_t2string(run->getend()) << " => " << time_t2string(newend) << endl;
|
||||
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LERR, msg.str().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
run->setstart(newstart);
|
||||
run->setend(newend);
|
||||
}
|
||||
|
||||
if(r == true)
|
||||
m_list.push_back(run);
|
||||
|
||||
pthread_mutex_unlock(&m_findmutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
void CRunlist::remove(CRunning *run)
|
||||
{
|
||||
pthread_mutex_lock(&m_findmutex);
|
||||
|
||||
list<CRunning *>::iterator itor;
|
||||
itor = find(m_list.begin(), m_list.end(), run);
|
||||
if (itor != m_list.end())
|
||||
{
|
||||
m_list.erase(itor);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_findmutex);
|
||||
}
|
||||
|
||||
bool CRunlist::findnewtime(time_t s, time_t e, time_t &ns, time_t &ne)
|
||||
{
|
||||
stringstream msg;
|
||||
bool r = false;
|
||||
ns = s;
|
||||
ne = e;
|
||||
|
||||
msg << "[running:"<< pthread_self() << "] Run list count : " << m_list.size() <<
|
||||
",input time : " << time_t2string(ns) << "," << time_t2string(ne);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << msg.str() << endl;
|
||||
#endif //_DEBUG
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
list<CRunning *>::iterator it;
|
||||
for ( it=m_list.begin() ; it != m_list.end(); it++ )
|
||||
{
|
||||
CRunning *pdata = static_cast<CRunning *>(*it);
|
||||
msg.str("");
|
||||
msg << "[running:"<< pthread_self() << "] get running :" <<
|
||||
time_t2string(pdata->getstart()) << "," << time_t2string(pdata->getend());
|
||||
#ifdef _DEBUG
|
||||
cout << msg.str() << endl;
|
||||
#endif //_DEBUG
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
if( ne > pdata->getend() )
|
||||
{
|
||||
if(ns >= pdata->getend() )
|
||||
{
|
||||
LOG(LDBG, "ne > pdata->getend(), ns >= pdata->getend()");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = true;
|
||||
|
||||
if( ns <= pdata->getstart() )
|
||||
{
|
||||
LOG(LDBG, "ne > pdata->getend(), ns < pdata->getend(), ns <= pdata->getstart() : ne = pdata->getstart()");
|
||||
ne = pdata->getstart();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LDBG, "ne > pdata->getend(), ns < pdata->getend(), ns > pdata->getstart() : new ne, ns");
|
||||
ne = pdata->getstart();
|
||||
ns = ne - (e - s);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( ne == pdata->getend() )
|
||||
{
|
||||
r = true;
|
||||
LOG(LDBG, "ne == pdata->getend(), ne = pdata->getstart();");
|
||||
ne = pdata->getstart();
|
||||
}
|
||||
else // ne < pdata->getend()
|
||||
{
|
||||
if(ne <= pdata->getstart() )
|
||||
{
|
||||
LOG(LDBG, "ne < pdata->getend(), ne <= pdata->getstart()");
|
||||
continue;
|
||||
}
|
||||
else // ne > pdata->getstart()
|
||||
{
|
||||
r = true;
|
||||
if(ns <= pdata->getstart() )
|
||||
{
|
||||
LOG(LDBG, "ne < pdata->getend(), ne > pdata->getstart(), ns <= pdata->getstart() : ne = pdata->getstart()");
|
||||
ne = pdata->getstart();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LDBG, "ne < pdata->getend(), ne > pdata->getstart(), ns > pdata->getstart() : new(2) ne ns");
|
||||
ne = pdata->getstart();
|
||||
ns = ne - (e - s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg.str("");
|
||||
msg << "[running:"<< pthread_self() << "] Find Time." <<
|
||||
time_t2string(ns) << "," << time_t2string(ne);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << msg.str() << endl;
|
||||
#endif // _DEBUG
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
time_t CRunlist::findnewtime(int findtype, time_t find)
|
||||
{
|
||||
time_t r = 0;
|
||||
//pthread_mutex_lock(&m_findmutex);
|
||||
|
||||
list<CRunning *>::iterator it;
|
||||
for ( it=m_list.begin() ; it != m_list.end(); it++ )
|
||||
{
|
||||
CRunning *pdata = static_cast<CRunning *>(*it);
|
||||
|
||||
switch(findtype)
|
||||
{
|
||||
case CRunlist::START_TIME:
|
||||
r = pdata->includestart(find);
|
||||
break;
|
||||
case CRunlist::EDN_TIME:
|
||||
r = pdata->includeend(find);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//pthread_mutex_unlock(&m_findmutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
// running
|
||||
CRunning::CRunning(CScheduler* sch, int task, time_t r)
|
||||
{
|
||||
m_scheduler = sch;
|
||||
m_taskindex = task;
|
||||
m_runed = r;
|
||||
m_starttime = 0;
|
||||
m_endtime = 0;
|
||||
}
|
||||
|
||||
CRunning::~CRunning()
|
||||
{
|
||||
}
|
||||
|
||||
void* CRunning::runfn(void* pdata)
|
||||
{
|
||||
CRunning* pObject = reinterpret_cast<CRunning *>(pdata);
|
||||
|
||||
pthread_detach( pthread_self() );
|
||||
|
||||
ostringstream msg;
|
||||
do
|
||||
{
|
||||
msg << "[running:" << pthread_self() << "] Task Index : "<<
|
||||
pObject->m_taskindex << " START.";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
msg.str("");
|
||||
|
||||
bool b = CRunlist::getInstance()->addlist(pObject);
|
||||
|
||||
if(b == false)
|
||||
{
|
||||
msg << "[running:" << pthread_self() <<"]Inserted into the run list failed.";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LERR, msg.str().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
pObject->m_scheduler->updatelastendtime(pObject->m_taskindex,
|
||||
pObject->m_endtime);
|
||||
|
||||
string cmd;
|
||||
cmd = cmd + " " + time_t2string(pObject->m_starttime) + " " +
|
||||
time_t2string(pObject->m_endtime);
|
||||
|
||||
msg << "call sync : " << cmd;
|
||||
|
||||
// sync 요청 처리
|
||||
// scheduler -> rc_syncd (local host)
|
||||
// 성공 실패 여부는 objRcSyncdRequest 객체 내부에서 로깅 처리 함.
|
||||
CRcSyncdRequest objRcSyncdRequest;
|
||||
objRcSyncdRequest.SendSyncRequest( SYNC_TYPE::NORMAL, time_t2string(pObject->m_starttime), time_t2string(pObject->m_endtime));
|
||||
|
||||
msg << "...Job End" ;
|
||||
LOG(LINF, msg.str().c_str());
|
||||
|
||||
|
||||
CRunlist::getInstance()->remove(pObject);
|
||||
}while( false );
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << " RUNNING END index - "<< pObject->m_taskindex << ",now (" <<
|
||||
time_t2string(pObject->m_runed) << ")"<< endl;
|
||||
#endif //_DEBUG
|
||||
msg.str("");
|
||||
msg << "[running:" << pthread_self() << "] END.";
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
msg.str("");
|
||||
|
||||
delete pObject;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
time_t CRunning::includestart(time_t s)
|
||||
{
|
||||
time_t t = 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
time_t CRunning::includeend(time_t e)
|
||||
{
|
||||
time_t t = 0;
|
||||
return t;
|
||||
}
|
||||
|
||||
bool CRunning::run(time_t s, time_t e)
|
||||
{
|
||||
m_starttime = s;
|
||||
m_endtime = e;
|
||||
|
||||
pthread_t thread;
|
||||
int nRet = pthread_create(&thread, 0, CRunning::runfn, this);
|
||||
if( nRet )
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "Running Thread create failed.[" << errno <<"]";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LERR, msg.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/***************************************************************************
|
||||
Running
|
||||
-----------------------------------------
|
||||
begin : 2011/11/01
|
||||
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.
|
||||
***************************************************************************/
|
||||
#ifndef __RUNNING_H__
|
||||
#define __RUNNING_H__
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class CScheduler;
|
||||
class CRunning;
|
||||
|
||||
class CRunlist
|
||||
{
|
||||
public:
|
||||
enum RUNLIST_FIND
|
||||
{
|
||||
START_TIME = 1,
|
||||
EDN_TIME = 2
|
||||
};
|
||||
|
||||
public:
|
||||
static CRunlist* getInstance();
|
||||
static void release();
|
||||
static void init();
|
||||
|
||||
bool addlist(CRunning *run);
|
||||
void remove(CRunning *run);
|
||||
|
||||
private:
|
||||
CRunlist();
|
||||
~CRunlist();
|
||||
|
||||
time_t findnewtime(int findtype, time_t find);
|
||||
bool findnewtime(time_t s, time_t e, time_t &ns, time_t &ne);
|
||||
|
||||
private:
|
||||
static CRunlist * m_inst;
|
||||
|
||||
list<CRunning*> m_list;
|
||||
|
||||
pthread_mutex_t m_findmutex;
|
||||
};
|
||||
|
||||
class CRunning
|
||||
{
|
||||
public:
|
||||
CRunning(CScheduler* scheduler, int task, time_t r);
|
||||
~CRunning();
|
||||
|
||||
bool run(time_t s, time_t e);
|
||||
|
||||
time_t includestart(time_t s);
|
||||
time_t includeend(time_t e);
|
||||
|
||||
void setstart(time_t t) { m_starttime = t; }
|
||||
void setend(time_t t) { m_endtime = t; }
|
||||
|
||||
time_t getstart() { return m_starttime; }
|
||||
time_t getend() { return m_endtime; }
|
||||
|
||||
private:
|
||||
static void* runfn( void* pdata );
|
||||
|
||||
private:
|
||||
time_t m_starttime;
|
||||
time_t m_endtime;
|
||||
time_t m_runed;
|
||||
|
||||
int m_taskindex;
|
||||
|
||||
CScheduler* m_scheduler;
|
||||
};
|
||||
|
||||
#endif // __RUNNING_H__
|
||||
@@ -0,0 +1,352 @@
|
||||
/***************************************************************************
|
||||
Scheduler
|
||||
-----------------------------------------
|
||||
begin : 2011/11/01
|
||||
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 "Scheduler.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
#include "Util.h"
|
||||
#include "Running.h"
|
||||
|
||||
|
||||
#define SHC_SLEEP_TIME (1000*1000)// microseconds
|
||||
#define DAY_SECOND (60*60*24) //
|
||||
|
||||
CScheduler::CScheduler()
|
||||
: m_exit(false)
|
||||
{
|
||||
pthread_mutex_init(&m_timermutex, NULL);
|
||||
pthread_cond_init(&m_timercond, NULL);
|
||||
|
||||
pthread_mutex_init(&m_workmutex, NULL);
|
||||
pthread_cond_init(&m_workcond, NULL);
|
||||
|
||||
pthread_mutex_init(&m_updatemutex, NULL);
|
||||
}
|
||||
|
||||
CScheduler::~CScheduler()
|
||||
{
|
||||
setexit(true);
|
||||
pthread_mutex_destroy(&m_timermutex);
|
||||
pthread_cond_destroy(&m_timercond);
|
||||
|
||||
pthread_mutex_destroy(&m_workmutex);
|
||||
pthread_cond_destroy(&m_workcond);
|
||||
|
||||
pthread_mutex_destroy(&m_updatemutex);
|
||||
}
|
||||
|
||||
void* CScheduler::WorkFn(void* pdata)
|
||||
{
|
||||
CScheduler* pObject = reinterpret_cast<CScheduler *>(pdata);
|
||||
|
||||
ostringstream msg;
|
||||
pthread_detach( pthread_self() );
|
||||
while( pObject->isexit() == false )
|
||||
{
|
||||
msg.str("");
|
||||
//pObject->whetherdetach();
|
||||
pthread_mutex_lock(&pObject->m_workmutex);
|
||||
int err = pthread_cond_wait(&pObject->m_workcond, &pObject->m_workmutex);
|
||||
|
||||
if ( err == 0 && pObject->isexit() == false)
|
||||
{
|
||||
pObject->whetherdetach();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(pObject->isexit())
|
||||
{
|
||||
msg << "Timer Work Thread exit.";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LERR, msg.str().c_str());
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&pObject->m_workmutex);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* CScheduler::TimerFn(void* pdata)
|
||||
{
|
||||
CScheduler* pObject = reinterpret_cast<CScheduler *>(pdata);
|
||||
|
||||
struct timeval nowtime;
|
||||
struct timespec timeout;
|
||||
ostringstream msg;
|
||||
#ifdef _DEBUG
|
||||
time_t t = time(NULL);
|
||||
#endif // _DEBUG
|
||||
|
||||
while( pObject->m_exit == false )
|
||||
{
|
||||
msg.str("");
|
||||
#ifdef _DEBUG
|
||||
cout << "scheduler::TimerFn..." << strtime_now() <<"("<< time(NULL)-t <<")" << endl;
|
||||
t = time(NULL);
|
||||
#endif // _DEBUG
|
||||
|
||||
int rc = pthread_mutex_lock(&pObject->m_timermutex);
|
||||
if(rc)
|
||||
{
|
||||
msg << "Timer pthread_mutex_lock error.[" << errno << "]. Timer exit.";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LCRT, msg.str().c_str());
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
gettimeofday(&nowtime, NULL);
|
||||
|
||||
timeout.tv_sec = nowtime.tv_sec + (SHC_SLEEP_TIME/1000000);
|
||||
timeout.tv_nsec = nowtime.tv_usec*1000 + (SHC_SLEEP_TIME%1000000*1000);
|
||||
rc = pthread_cond_timedwait(&pObject->m_timercond, &pObject->m_timermutex, &timeout);
|
||||
|
||||
switch(rc)
|
||||
{
|
||||
case ETIMEDOUT:
|
||||
msg << "Timer wake up. Thread signal workfn.";
|
||||
#ifdef _DEBUG
|
||||
cout << " " << msg.str() <<endl;
|
||||
#endif // _DEBUG
|
||||
LOG(LDEV2, msg.str().c_str());
|
||||
pthread_mutex_lock(&pObject->m_workmutex);
|
||||
pthread_cond_signal(&pObject->m_workcond);
|
||||
pthread_mutex_unlock(&pObject->m_workmutex);
|
||||
break;
|
||||
case 0:
|
||||
msg << "Timer Kill signaled.[m_exit :" << pObject->m_exit << "]";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LCRT, msg.str().c_str());
|
||||
break;
|
||||
default:
|
||||
msg << "Timer some error occurred.";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LALT, msg.str().c_str());
|
||||
break;
|
||||
}
|
||||
pthread_mutex_unlock(&pObject->m_timermutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CScheduler::run()
|
||||
{
|
||||
ostringstream msg;
|
||||
int nRet = pthread_create(&m_htimerthread, 0, CScheduler::TimerFn, this);
|
||||
if( nRet )
|
||||
{
|
||||
msg << "Timer Thread create failed.[ " << errno <<"]";
|
||||
cerr << msg << endl;
|
||||
LOG(LCRT, msg.str().c_str());
|
||||
return -1;
|
||||
}
|
||||
|
||||
nRet = pthread_create(&m_hworkthread, 0, CScheduler::WorkFn, this);
|
||||
if( nRet )
|
||||
{
|
||||
msg << "Timer Work Thread create failed.[ " << errno <<"]";
|
||||
cerr << msg << endl;
|
||||
LOG(LCRT, msg.str().c_str());
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CScheduler::addtask(short tasktype, int val)
|
||||
{
|
||||
task_info info;
|
||||
info.tasktype = tasktype;
|
||||
info.timeval.interval = val;
|
||||
|
||||
int i = m_taskmap.size();
|
||||
m_taskmap.insert(make_pair(i,info));
|
||||
return true;
|
||||
}
|
||||
|
||||
void CScheduler::printtasklist()
|
||||
{
|
||||
map<int, task_info>::iterator iter;
|
||||
for( iter = m_taskmap.begin(); !m_taskmap.empty()&& iter != m_taskmap.end(); iter++ )
|
||||
{
|
||||
cout << "Task List index : "<< iter->first << ", Taks info : " << iter->second.tasktype << "," <<
|
||||
iter->second.timeval.interval << "," << iter->second.lastendtime << "," << iter->second.lastruntime << endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool CScheduler::whetherdetach()
|
||||
{
|
||||
ostringstream msg;
|
||||
time_t nowtime;
|
||||
time ( &nowtime );
|
||||
map<int, task_info>::iterator iter;
|
||||
|
||||
for( iter = m_taskmap.begin(); !m_taskmap.empty()&& iter != m_taskmap.end(); iter++ )
|
||||
{
|
||||
msg.str("");
|
||||
task_info &task = iter->second;
|
||||
task.spendtime += SHC_SLEEP_TIME;
|
||||
|
||||
if( task.lastruntime - nowtime > 0 )
|
||||
{
|
||||
msg << "Task last runtime correction. " <<
|
||||
time_t2string(task.lastruntime) << " => " << time_t2string(nowtime);
|
||||
#ifdef _DEBUG
|
||||
cout << msg.str() << endl;
|
||||
#endif // _DEBUG
|
||||
LOG(LNOT, msg.str().c_str());
|
||||
task.lastruntime = nowtime;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << " now time - " << time_t2string(nowtime) << ", task index - " << iter->first <<
|
||||
", spend time - " << task.spendtime << ",(" << nowtime- task.lastruntime << ")"
|
||||
", last run time - " << time_t2string(task.lastruntime) << ", time value - " <<
|
||||
(task.tasktype == CScheduler::TIME_INTERVAL ? "interval" : "once") << "," <<
|
||||
(task.tasktype == CScheduler::TIME_INTERVAL ? task.timeval.interval : task.timeval.hour) << endl;
|
||||
#endif // _DEBUG
|
||||
|
||||
bool detach = false;
|
||||
switch( task.tasktype )
|
||||
{
|
||||
case CScheduler::TIME_INTERVAL:
|
||||
{
|
||||
int spendtime = nowtime - task.lastruntime;
|
||||
//int64_t spendtime = task.spendtime/1000000;
|
||||
|
||||
if( (task.lastruntime == 0) || ( spendtime >= task.timeval.interval ) )
|
||||
{
|
||||
// 첫번째 등록된 작업이 먼저 수행될 수 있도록 sleep 수행함
|
||||
solusleep(1000);
|
||||
|
||||
task.spendtime = 0;
|
||||
//task.spendtime = SHC_SLEEP_TIME;
|
||||
task.lastruntime = nowtime;
|
||||
detach = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CScheduler::TIME_ONCE:
|
||||
{
|
||||
string nowstr = time_t2string(nowtime);
|
||||
int hours = atoi(nowstr.substr(8,2).c_str());
|
||||
string nowhour = nowstr.substr(0,8);
|
||||
string lastrunhour = time_t2string(task.lastruntime).substr(0,8);
|
||||
|
||||
if( hours == task.timeval.hour && nowhour > lastrunhour)
|
||||
{
|
||||
task.spendtime = 0;
|
||||
task.lastruntime = nowtime;
|
||||
detach = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msg.str("");
|
||||
msg << "Unknown Task info.";
|
||||
cerr << msg.str() << endl;
|
||||
LOG(LWAR, msg.str().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if( detach == true )
|
||||
{
|
||||
msg.str("");
|
||||
msg << "Task index : " << iter->first << ", now time - "<< nowtime <<
|
||||
"," << iter->second.lastruntime <<", Running detach....";
|
||||
#ifdef _DEBUG
|
||||
cout << msg.str() << endl;
|
||||
#endif // _DEBUG
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
time_t start, end;
|
||||
CRunning * prun = new CRunning(this, iter->first, task.lastruntime);
|
||||
pthread_mutex_lock(&m_updatemutex);
|
||||
|
||||
end = nowtime - CServiceConfig::GetInstance()->GetSafetyFactor();
|
||||
|
||||
if(task.lastendtime == 0)
|
||||
{
|
||||
if (task.tasktype == CScheduler::TIME_ONCE)
|
||||
{
|
||||
start = end - (CServiceConfig::GetInstance()->GetOnceSize() * DAY_SECOND);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = end - task.timeval.interval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start = task.lastendtime;
|
||||
|
||||
if (task.tasktype == CScheduler::TIME_ONCE)
|
||||
{
|
||||
time_t newstart = end - (CServiceConfig::GetInstance()->GetOnceSize() * DAY_SECOND);
|
||||
if( start < newstart )
|
||||
start = newstart;
|
||||
}
|
||||
}
|
||||
|
||||
if( prun->run(start, end) == false)
|
||||
{
|
||||
}
|
||||
pthread_mutex_unlock(&m_updatemutex);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CScheduler::setexit(bool v)
|
||||
{
|
||||
LOG(LINF, "setexit %d", v);
|
||||
m_exit = v;
|
||||
// kill timer
|
||||
pthread_mutex_lock(&m_timermutex);
|
||||
pthread_cond_signal(&m_timercond);
|
||||
pthread_mutex_unlock(&m_timermutex);
|
||||
|
||||
// kill work
|
||||
pthread_mutex_lock(&m_workmutex);
|
||||
pthread_cond_signal(&m_workcond);
|
||||
pthread_mutex_unlock(&m_workmutex);
|
||||
}
|
||||
|
||||
|
||||
bool CScheduler::updatelastendtime(int taskindex, time_t newtime)
|
||||
{
|
||||
pthread_mutex_lock(&m_updatemutex);
|
||||
|
||||
map<int, task_info>::iterator iter = m_taskmap.find(taskindex);
|
||||
if( iter != m_taskmap.end() )
|
||||
{
|
||||
LOG(LDBG, "Taks index %d,%s => %s", taskindex,
|
||||
time_t2string(iter->second.lastendtime).c_str(),
|
||||
time_t2string(newtime).c_str());
|
||||
|
||||
if( iter->second.lastendtime < newtime )
|
||||
{
|
||||
iter->second.lastendtime = newtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "The current setting(Task index - ("<< taskindex <<
|
||||
"), last endtime) is less than new endtime." << endl;
|
||||
#endif // _DEBUG
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_updatemutex);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/***************************************************************************
|
||||
Scheduler
|
||||
-----------------------------------------
|
||||
begin : 2011/11/01
|
||||
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.
|
||||
***************************************************************************/
|
||||
#ifndef __SCHEDULER_H__
|
||||
#define __SCHEDULER_H__
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct task_info
|
||||
{
|
||||
short tasktype;
|
||||
int64_t spendtime;
|
||||
union
|
||||
{
|
||||
int interval;
|
||||
int hour;
|
||||
}timeval;
|
||||
time_t lastendtime;
|
||||
time_t lastruntime;
|
||||
task_info()
|
||||
: tasktype(-1), spendtime(0), lastendtime(0), lastruntime(0) {}
|
||||
} ;
|
||||
|
||||
typedef struct task_info task_info;
|
||||
|
||||
class CScheduler
|
||||
{
|
||||
public:
|
||||
enum TASK_TYPE
|
||||
{
|
||||
TIME_UNKNOWN = -1,
|
||||
TIME_ONCE = 0,
|
||||
TIME_INTERVAL = 1
|
||||
};
|
||||
|
||||
public:
|
||||
CScheduler();
|
||||
~CScheduler();
|
||||
|
||||
int run();
|
||||
|
||||
bool addtask(short tasktype, int val);
|
||||
pthread_t gettimerhandle() {return m_htimerthread;}
|
||||
bool whetherdetach();
|
||||
bool updatelastendtime(int taskindex, time_t newtime);
|
||||
|
||||
void printtasklist();
|
||||
|
||||
void setexit(bool v);
|
||||
bool isexit() { return m_exit; }
|
||||
|
||||
private:
|
||||
static void* TimerFn(void* pdata);
|
||||
static void* WorkFn(void* pdata);
|
||||
|
||||
private:
|
||||
bool m_exit;
|
||||
map<int, task_info> m_taskmap;
|
||||
|
||||
pthread_t m_htimerthread;
|
||||
pthread_cond_t m_timercond;
|
||||
pthread_mutex_t m_timermutex;
|
||||
|
||||
pthread_t m_hworkthread;
|
||||
pthread_cond_t m_workcond;
|
||||
pthread_mutex_t m_workmutex;
|
||||
|
||||
pthread_mutex_t m_updatemutex;
|
||||
};
|
||||
|
||||
|
||||
#endif // __SCHEDULER_H__
|
||||
@@ -0,0 +1,448 @@
|
||||
#include "ServiceConfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
// static 변수 초기화
|
||||
CServiceConfig * CServiceConfig::m_pInstance = NULL;
|
||||
|
||||
|
||||
// 생성자
|
||||
CServiceConfig::CServiceConfig()
|
||||
{
|
||||
// default 값 설정.
|
||||
// 지정된 conf 파일에 해당 설정이 없어도 동작되도록 처리할 값에 대해서만 default 값을 정의한다.
|
||||
m_nChkSmall = 60;
|
||||
m_nChkMiddle = 3600;
|
||||
m_strDiffCommand = "/user/service/etc/diff_com.sh";
|
||||
m_strRcCMove = "/user/service/bin/rc_cmove";
|
||||
m_vecFHSMount.push_back("/stg/node0");
|
||||
m_vecFHSMount.push_back("/stg/node1");
|
||||
m_vecFHSMount.push_back("/stg/node2");
|
||||
}
|
||||
|
||||
// 소멸자
|
||||
CServiceConfig::~CServiceConfig()
|
||||
{
|
||||
// 객체 소멸시...
|
||||
// 만약 static GetInstance() 함수가 가르키는 객체가 자기 자신이라면...
|
||||
// 소멸 처리에 의해 문제가 발생할 수 있으므로... 이에 대한 처리를 해 준다.
|
||||
if( CServiceConfig::GetInstance() == this )
|
||||
{
|
||||
CServiceConfig::m_pInstance = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CServiceConfig::Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
|
||||
{
|
||||
|
||||
// 1. 임시 처리용 Instance 를 생성한다.
|
||||
CServiceConfig * pTempInstance = new CServiceConfig();
|
||||
|
||||
// 2. 전달 받은 Config 정보를 임시 Instance 로 로딩한다.
|
||||
// - 만약 로딩이 실패할 경우... 임시 Instance 객체를 삭제 처리한다.
|
||||
if( pTempInstance->Load( strProgramName, strConfFileName, strErrorMessage ) == false )
|
||||
{
|
||||
delete pTempInstance;
|
||||
pTempInstance = NULL;
|
||||
|
||||
return false; // 생성 실패 사유는 Error String 관련 함수를 사용하여 확인.
|
||||
}
|
||||
|
||||
// 3. 전달받은 Conf 정보 로딩에 성공한 경우...
|
||||
// - 기존 Instance 객체가 존재하는 경우.. 교체 처리..
|
||||
// - 기존 Instance 객체가 없는 경우는 신규 Instance 사용토록 처리.
|
||||
if( CServiceConfig::GetInstance() == NULL )
|
||||
{
|
||||
CServiceConfig::m_pInstance = pTempInstance;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Instance replace...
|
||||
CServiceConfig * pPreviosInstance = CServiceConfig::m_pInstance;
|
||||
CServiceConfig::m_pInstance = pTempInstance;
|
||||
|
||||
delete pPreviosInstance;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
CServiceConfig * CServiceConfig::GetInstance( )
|
||||
{
|
||||
return CServiceConfig::m_pInstance;
|
||||
}
|
||||
|
||||
|
||||
// 각 항목별 제약값은 기존 service_sync 모듈 소스를 참고하여 정의함.
|
||||
bool CServiceConfig::Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage )
|
||||
{
|
||||
// 변수 유효성 확인
|
||||
if( strProgramName.size() <= 0 )
|
||||
{
|
||||
strErrorMessage = "Config Program Name[" + strProgramName + "] not valid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Config class (lib 하위) 를 이용하여 config 파일 상의 정보를 로딩 처리
|
||||
Config conf;
|
||||
|
||||
if( conf.Open( strConfFileName ) == false )
|
||||
{
|
||||
strErrorMessage = "Config file[" + strConfFileName + "] open failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Config 모듈에 로딩된 정보 중 필요한 정보만 가져온다...
|
||||
// - 만약 오류가 발생할 경우... 해당 내역은 Error String 에 저장 처리...
|
||||
|
||||
std::string strValue;
|
||||
int nValue;
|
||||
std::vector< std::string > vecValue;
|
||||
|
||||
|
||||
// Log path
|
||||
if( GetConfigValue( conf, strProgramName, "DEFAULT_LOG_DIR", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strLogPath = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// Log Level
|
||||
if( GetConfigValue( conf, strProgramName, "LOG_LEVEL", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 || nValue > MAX_LOG_LEVEL )
|
||||
{
|
||||
strErrorMessage = "Config [LOG_LEVEL] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nLogLevel = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RC ID
|
||||
if( GetConfigValue( conf, strProgramName, "RC_ID", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcId = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB IP
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_IP", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbIp = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB PORT
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_PORT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue <= 0 || nValue > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [RCDB_PORT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nRcdbPort = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB DB NAME
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_DB_NAME", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbName = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB ACCOUNT
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_ACCT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbAcct = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RCDB ACCOUNT PASSWORD
|
||||
if( GetConfigValue( conf, strProgramName, "RCDB_ACCT_PW", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_strRcdbAcctPw = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// Skip keyword : h|path (head) or m|path(middle) or t|path(tail)
|
||||
// - 본 설정갑은 없어도 동작하도록 처리한다.
|
||||
if( conf.GetConfig( strProgramName, "SKIP_KEYWORD", vecValue ) == true )
|
||||
{
|
||||
// 해당 값이 존재할 경우..
|
||||
// Multi value 이므로 갯수 검사
|
||||
if( vecValue.size() > 0 )
|
||||
{
|
||||
m_vecSkipWord = vecValue;
|
||||
}
|
||||
|
||||
vecValue.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// program section 에 존재하지 않을 경우... COMMON 세션 확인
|
||||
if( conf.GetConfig( "COMMON", "SKIP_KEYWORD", vecValue ) == true )
|
||||
{
|
||||
// 해당 값이 존재할 경우..
|
||||
// Multi value 이므로 갯수 검사
|
||||
if( vecValue.size() > 0 )
|
||||
{
|
||||
m_vecSkipWord = vecValue;
|
||||
}
|
||||
|
||||
vecValue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Operator Command Port, OP_PORT = 14002
|
||||
if( GetConfigValue( conf, strProgramName, "OP_PORT", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue <= 0 || nValue > 65535 )
|
||||
{
|
||||
strErrorMessage = "Config [OP_PORT] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nOperationPort = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// Database connection pool count, DB_POOL = 4
|
||||
if( GetConfigValue( conf, strProgramName, "DB_POOL", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 )
|
||||
{
|
||||
strErrorMessage = "Config [DB_POOL] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nDbPoolCount = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// Work pool count, WORK_POOL = 20
|
||||
if( GetConfigValue( conf, strProgramName, "WORK_POOL", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 )
|
||||
{
|
||||
strErrorMessage = "Config [WORK_POOL] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nWorkPoolCount = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// When endtime to obtain coefficient that are subtracted. (sec), SAFETY_FACTOR = 180
|
||||
if( GetConfigValue( conf, strProgramName, "SAFETY_FACTOR", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 )
|
||||
{
|
||||
strErrorMessage = "Config [SAFETY_FACTOR] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nSafetyFactor = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// Get the set amount of time at a time. (Day), ONCE_SIZE = 1
|
||||
// 1 이상이어야 한다.
|
||||
if( GetConfigValue( conf, strProgramName, "ONCE_SIZE", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue <= 0 )
|
||||
{
|
||||
strErrorMessage = "Config [ONCE_SIZE] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nOnceSize = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// CHK_SMALL = 60 , range : 30 ~CHK_MIDDLE (second)
|
||||
// Default 값 존재, 최소 30 이상어야 한다.
|
||||
if( GetConfigValue( conf, strProgramName, "CHK_SMALL", strValue, strErrorMessage ) == true )
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 30 )
|
||||
{
|
||||
strErrorMessage = "Config [CHK_SMALL] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nChkSmall = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// CHK_MIDDLE = 3600, range : CHK_SMALL ~(second),
|
||||
// Default 값 존재, CHK_SMALL 값보다 커야 한다.
|
||||
if( GetConfigValue( conf, strProgramName, "CHK_MIDDLE", strValue, strErrorMessage ) == true )
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 )
|
||||
{
|
||||
strErrorMessage = "Config [CHK_MIDDLE] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else if( nValue <= (int) m_nChkSmall )
|
||||
{
|
||||
strErrorMessage = "Config [CHK_MIDDLE] value[" + strValue + "] less then [CHK_SMALL][";
|
||||
strErrorMessage += m_nChkSmall;
|
||||
strErrorMessage += "]";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nChkMiddle = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// CHK_ONCE = 7, range : 1Days, hour( 0 - 23 )
|
||||
// 0 ~ 23 구간내 값이어야 한다.
|
||||
if( GetConfigValue( conf, strProgramName, "CHK_ONCE", strValue, strErrorMessage ) == false )
|
||||
return false;
|
||||
else
|
||||
{
|
||||
nValue = atoi(strValue.c_str());
|
||||
if( nValue < 0 || nValue > 23)
|
||||
{
|
||||
strErrorMessage = "Config [CHK_ONCE] value[" + strValue + "] is not valid";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_nChkOnce = nValue;
|
||||
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
|
||||
// DIFF_COMMAND=/user/service/etc/diff_com.sh
|
||||
// Default 값 존재
|
||||
if( GetConfigValue( conf, strProgramName, "DIFF_COMMAND", strValue, strErrorMessage ) == true )
|
||||
{
|
||||
m_strDiffCommand = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// RC_CMOVE=/user/service/bin/rc_cmove
|
||||
// Default 값 존재
|
||||
if (GetConfigValue(conf, strProgramName, "RC_CMOVE", strValue, strErrorMessage) == true)
|
||||
{
|
||||
m_strRcCMove = strValue;
|
||||
strValue.clear();
|
||||
}
|
||||
|
||||
// FHS_STORAGE_MOUNT = /stg/node0,/stg/node1,/stg/node2
|
||||
// Default 값 존재
|
||||
if (conf.GetConfig(strProgramName, "FHS_STORAGE_MOUNT", vecValue) == true)
|
||||
{
|
||||
// 해당 값이 존재할 경우..
|
||||
// Multi value 이므로 갯수 검사
|
||||
if (vecValue.size() > 0)
|
||||
{
|
||||
m_vecFHSMount = vecValue;
|
||||
}
|
||||
|
||||
vecValue.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// program section 에 존재하지 않을 경우... COMMON 세션 확인
|
||||
if (conf.GetConfig("COMMON", "FHS_STORAGE_MOUNT", vecValue) == true)
|
||||
{
|
||||
// 해당 값이 존재할 경우..
|
||||
// Multi value 이므로 갯수 검사
|
||||
if (vecValue.size() > 0)
|
||||
{
|
||||
m_vecFHSMount = vecValue;
|
||||
}
|
||||
|
||||
vecValue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// conf 정보 로딩이 모두 정상적으로 완료된 경우...
|
||||
// 마지막으로 전달받은 config 명, section 정보를 저장한다.
|
||||
m_strConfigFileName = strConfFileName;
|
||||
m_strProgramName = strProgramName;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CServiceConfig::GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage )
|
||||
{
|
||||
// conf get value
|
||||
if( conf.GetConfig( strProgramName, strKey, strValue) == false )
|
||||
{
|
||||
if( conf.GetConfig( "COMMON", strKey, strValue) == false )
|
||||
{
|
||||
strErrorMessage = "Config [" + strKey + "] value is not exist";
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// value check.
|
||||
if( strValue.empty() == true )
|
||||
{
|
||||
strErrorMessage = "Config [" + strKey + "] value is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/****************************************************************************
|
||||
rc_syncd's service config module
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SERVICE_CONFIG_H__
|
||||
#define __SERVICE_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
// 본 모듈은 conf 파일의 정보를 read 하여... 본 프로세스 관련 설정 정보를 저장한다.
|
||||
// 본 모듈은 singleton 으로 동작시켜 Main 프로세스 및 Worker 프로세스에서도 접근이 가능토록 한다.
|
||||
// conf 파일에 대한 파싱 및 설정 정보 추출은 lib 하위의 Config 클래스를 이용한다.
|
||||
// 본 객체는 singleton 객체이므로 상속받아 사용하지 않도록 한다. ( 상속받아 사용할 수 없도록 private 처리함 )
|
||||
|
||||
class CServiceConfig
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// sigleton 객체 생성을 위해 생성자를 public 으로 처리하지 않음.
|
||||
CServiceConfig();
|
||||
|
||||
// 소멸자
|
||||
virtual ~CServiceConfig();
|
||||
|
||||
static CServiceConfig * m_pInstance;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 객체 초기화 처리용 Function.
|
||||
// 본 함수 호출시 Instance 생성 후 입력 받은 Config 파일 load.
|
||||
// 따라서 본 함수를 호출하지 않을 경우.. GetInstance() 함수는 NULL 을 반환
|
||||
// 본 함수를 객체가 생성된 상태에서 재 호출할 경우
|
||||
// - 주어진 Conf 파일 정보가 정확하다면.. conf 정보를 다시 load 함.
|
||||
// - 주어진 conf 파일 정보가 부정확하다면... 이전 conf 를 계속 사용함.
|
||||
static bool Init( const std::string strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
|
||||
|
||||
// Singleton 객체 접근 메소드
|
||||
static CServiceConfig * GetInstance();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 전달받은 conf 파일에서 해당 config 정보를 로드하여 멤버 변수에 저장한다.
|
||||
// 만약 반환값이 false 인 경우 해당 오류 관련 내역은 strErrorMessage 변수에 저장된다.
|
||||
bool Load( const std::string & strProgramName, const std::string & strConfFileName, std::string & strErrorMessage );
|
||||
|
||||
|
||||
// Config 객체로 부터 지정된 strKey 정보를 가져와 유효성 여부를 판단.
|
||||
// 반환값이 false 인 경우 strErrorMessage 상에 오류 내역이 저장된다.
|
||||
bool GetConfigValue( Config & conf, const std::string & strProgramName, const std::string strKey, std::string & strValue, std::string & strErrorMessage );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// 객체 초기화시 전달받은 정보
|
||||
std::string m_strConfigFileName; // 설정 파일 정보
|
||||
std::string m_strProgramName; // 프로그램 명 (conf 상에서 해당 프로그램의 설정 정보를 가져올 때 사용)
|
||||
|
||||
// 기본 설정 정보.
|
||||
std::string m_strLogPath; // 로그 저장 Path
|
||||
int m_nLogLevel; // 로그 기록 Level
|
||||
|
||||
std::string m_strRcId; // RC ID
|
||||
|
||||
std::string m_strRcdbIp; // RCDB IP
|
||||
unsigned int m_nRcdbPort; // RCDB Port
|
||||
std::string m_strRcdbName; // RCDB DB Name
|
||||
std::string m_strRcdbAcct; // RCDB 접근 계정
|
||||
std::string m_strRcdbAcctPw; // RCDB 접근 Password.
|
||||
|
||||
std::vector<std::string> m_vecSkipWord; // 작업 대상에서 제외할 content 문자열 정보 저장.
|
||||
// 설정값이 존재하지 않을 수 있음.
|
||||
|
||||
// Process
|
||||
unsigned int m_nOperationPort; // Operation Command TCP Listen port, OP_PORT = 14002
|
||||
unsigned int m_nDbPoolCount; // Database connection pool count, DB_POOL = 4
|
||||
unsigned int m_nWorkPoolCount; // Work pool count, WORK_POOL = 20
|
||||
unsigned int m_nSafetyFactor; // When endtime to obtain coefficient that are subtracted. (sec), SAFETY_FACTOR = 180
|
||||
unsigned int m_nOnceSize; // Get the set amount of time at a time. (Day), ONCE_SIZE = 1
|
||||
|
||||
// Time between sync runs & target interval
|
||||
unsigned int m_nChkSmall; // range : 30 ~CHK_MIDDLE( second ), CHK_SMALL = 60
|
||||
// default : 60
|
||||
|
||||
unsigned int m_nChkMiddle; // range : CHK_SMALL ~(second), CHK_MIDDLE = 3600
|
||||
// default : 3600
|
||||
|
||||
unsigned int m_nChkOnce; // range : 1Days, hour( 0 - 23 ), CHK_ONCE = 7
|
||||
|
||||
std::string m_strDiffCommand; // diff commnad, DIFF_COMMAND=/user/service/etc/diff_com.sh
|
||||
// default : /user/service/etc/diff_com.sh
|
||||
|
||||
std::string m_strRcCMove; // rc_cmove path, RC_CMOVE=/user/service/bin/rc_cmove
|
||||
// default : /user/service/bin/rc_cmove
|
||||
|
||||
std::vector<std::string> m_vecFHSMount; // FHS storage mount info multi set enable, FHS_STORAGE_MOUNT = /stg/node0,/stg/node1,/stg/node2
|
||||
// default : /stg/node0,/stg/node1,/stg/node2
|
||||
|
||||
public: // 멤버 변수에 대한 Get 함수 선언 및 정의
|
||||
|
||||
const char * GetConfigFileName() { return m_strConfigFileName.c_str(); }
|
||||
const char * GetProgramName() { return m_strProgramName.c_str(); }
|
||||
|
||||
const char * GetLogPath() { return m_strLogPath.c_str(); }
|
||||
int GetLogLevel() { return m_nLogLevel; }
|
||||
|
||||
const char * GetRcId() { return m_strRcId.c_str(); }
|
||||
|
||||
const char * GetRcdbIp() { return m_strRcdbIp.c_str(); }
|
||||
unsigned int GetRcdbPort() { return m_nRcdbPort; }
|
||||
const char * GetRcdbName() { return m_strRcdbName.c_str(); }
|
||||
const char * GetRcdbAcct() { return m_strRcdbAcct.c_str(); }
|
||||
const char * GetRcdbAcctPw() { return m_strRcdbAcctPw.c_str(); }
|
||||
|
||||
std::vector<std::string> GetSkipWord() { return m_vecSkipWord; }
|
||||
|
||||
unsigned int GetOperationPort() { return m_nOperationPort; }
|
||||
unsigned int GetDbPoolCount() { return m_nDbPoolCount; }
|
||||
unsigned int GetWorkPoolCount() { return m_nWorkPoolCount; }
|
||||
unsigned int GetSafetyFactor() { return m_nSafetyFactor; }
|
||||
unsigned int GetOnceSize() { return m_nOnceSize; }
|
||||
|
||||
unsigned int GetChkSmall() { return m_nChkSmall; }
|
||||
unsigned int GetChkMiddle() { return m_nChkMiddle; }
|
||||
unsigned int GetChkOnce() { return m_nChkOnce; }
|
||||
|
||||
const char * GetDiffCommand() { return m_strDiffCommand.c_str(); }
|
||||
const char * GetRCCMoveCommand() { return m_strRcCMove.c_str(); }
|
||||
|
||||
std::vector<std::string> GetFHSMount() { return m_vecFHSMount; }
|
||||
};
|
||||
|
||||
#endif /* __SERVICE_CONFIG_H__ */
|
||||
@@ -0,0 +1,477 @@
|
||||
/***************************************************************************
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
// 전체 자료량 구하지 못했을 때 해당 값 사용
|
||||
#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<CSourceData*>(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<string> skipwords = CServiceConfig::GetInstance()->GetSkipWord();
|
||||
int keycnt = skipwords.size();
|
||||
|
||||
|
||||
for( int i=0; i< keycnt; ++i )
|
||||
{
|
||||
string k = skipwords[i];
|
||||
vector<string> 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
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.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __SOURCE_DATA_H__
|
||||
#define __SOURCE_DATA_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
|
||||
#include "DataFile.h"
|
||||
#include "SyncList.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class DataBase;
|
||||
|
||||
class CSourceData
|
||||
{
|
||||
private:
|
||||
pthread_t m_handleThread; // 스레드 핸들
|
||||
CSyncInfo m_sourceParam; // sync info
|
||||
CDataFile m_dataFile; // 파일저장시 사용할 객체
|
||||
bool m_bDELETED_YN; // bDELETED_YN값이 true일때 deleted_yn = 'N' 조회
|
||||
bool m_usedisplay; // 신규형상(9.3)에서는 display_name 사용하며, 기존 uri 값과 동일한 값
|
||||
bool m_ismaster; // master / slave 여부
|
||||
|
||||
// 에러 메시지를 담는다.
|
||||
// 주의 : 호출한 함수에서 isError() 를 통해 에러 처리를 따로하므로, 에러가 아닌 경우에 변수에 값을 담으면 안된다.
|
||||
string m_strErrorMessage;
|
||||
|
||||
public:
|
||||
CSourceData();
|
||||
~CSourceData();
|
||||
|
||||
protected:
|
||||
static void* Run(void* arg); // 스레드 시작
|
||||
|
||||
bool IsSkipKeyword(string key); // uri에 skip keyword 포함 유무 체크
|
||||
|
||||
string GetTargetTable(DataBase *d);
|
||||
|
||||
int64_t GetRows(DataBase *d, const char* tblname);
|
||||
|
||||
inline void SetErrorMessage(const string strErrorMessage)
|
||||
{ m_strErrorMessage = strErrorMessage; }
|
||||
|
||||
public:
|
||||
// thread 초기화
|
||||
bool Init(bool master, CSyncInfo sourceParam);
|
||||
|
||||
// thread 실행
|
||||
bool Execute();
|
||||
|
||||
// 호출측에서 Thread의 종료 여부등을 판단하기 위함
|
||||
inline pthread_t* GetThreadHandle()
|
||||
{ return &m_handleThread; }
|
||||
|
||||
inline string GetMetaFilePath()
|
||||
{ return m_dataFile.GetFilePath(); }
|
||||
|
||||
inline bool isError(string & errmsg )
|
||||
{
|
||||
errmsg = m_strErrorMessage; return bool(m_strErrorMessage.size() > 0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __SOURCE_DATA_H__
|
||||
@@ -0,0 +1,215 @@
|
||||
#include "SyncList.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Database.h"
|
||||
#include "DBConnPool.h"
|
||||
#include "Logger.h"
|
||||
#include "ReportLog.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SYNC_FILE_PATH "/user/service/_sync"
|
||||
|
||||
// CSyncInfo class
|
||||
CSyncInfo::CSyncInfo()
|
||||
{
|
||||
}
|
||||
|
||||
CSyncInfo::~CSyncInfo()
|
||||
{
|
||||
}
|
||||
|
||||
void CSyncInfo::UnlinkFile()
|
||||
{
|
||||
unlink(file_master_name.c_str());
|
||||
unlink(file_slave_name.c_str());
|
||||
unlink(file_diff_name.c_str());
|
||||
|
||||
if (sync_type < SYNC_TYPE::CHK_ONLY )
|
||||
unlink(file_sync_name.c_str());
|
||||
}
|
||||
|
||||
// CSyncLinst class
|
||||
CSyncList::CSyncList()
|
||||
{
|
||||
}
|
||||
|
||||
CSyncList::~CSyncList()
|
||||
{
|
||||
m_list.clear();
|
||||
}
|
||||
|
||||
bool CSyncList::CreateList(CReqMasterData & d)
|
||||
{
|
||||
// Sync Info from RCDB
|
||||
DataBase *db = CMasterDBPool::getInstance()->GetConnFromPool();
|
||||
|
||||
if (!db)
|
||||
{
|
||||
LOG(LERR, "Failed GetDB.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ostringstream sql;
|
||||
|
||||
sql << "SELECT";
|
||||
sql << " S.sp_svc_tran_id, S.master_yn, S.linked_sp_svc_tran_id, S.linked_rcts, P.sp_svc_tran_id, P.uri_ignore_case ";
|
||||
sql << " FROM t_sms_sp_svc_product_sync S ";
|
||||
sql << " LEFT JOIN t_sms_sp_svc_product P ON(S.sp_svc_tran_id = P.sp_svc_tran_id) ";
|
||||
|
||||
if (d.one_service.empty())//d.service_list.empty())
|
||||
{
|
||||
// All
|
||||
}
|
||||
else
|
||||
{
|
||||
string s = d.one_service;
|
||||
// part
|
||||
/*
|
||||
for (list<string>::iterator list_iter = d.service_list.begin();
|
||||
list_iter != d.service_list.end(); list_iter++)
|
||||
{
|
||||
if (list_iter != d.service_list.begin())
|
||||
s += ",";
|
||||
s += *list_iter;
|
||||
}
|
||||
*/
|
||||
sql << " WHERE P.sp_svc_tran_id IN (" << s << ")";
|
||||
}
|
||||
|
||||
db->PgDoExec((char*)sql.str().c_str());
|
||||
|
||||
if (db->PgResult(DataBase::NOT_CLEAR) < 0)
|
||||
{
|
||||
|
||||
LOG(LERR, " Failed Get Sync List. %s", db->GetErrorMessage().c_str());
|
||||
db->PgClear();
|
||||
CMasterDBPool::getInstance()->ReleaseConnToPool(db, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < db->GetNoTuples(); ++i)
|
||||
{
|
||||
CSyncInfo t;
|
||||
if (strlen(db->GetValue(i, 4)) <= 0)
|
||||
{
|
||||
//LOG(LNOT, "Not Found Service.[tran_id :%s]", db->GetValue(i, 0));
|
||||
|
||||
CReportLog rlog;
|
||||
|
||||
if (rlog.Init(CServiceConfig::GetInstance()->GetLogPath()))
|
||||
{
|
||||
rlog.Write("NOT", "[%s] [Not Found Sync Service in Product Table.[tran_id :%s]]", PROG_NAME, db->GetValue(i, 0));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// master
|
||||
if (strcmp(db->GetValue(i, 1), "Y") == 0)
|
||||
{
|
||||
t.uri_ignore_case = db->GetValue(i, 5);
|
||||
|
||||
t.start_time = d.start_time;
|
||||
t.end_time = d.end_time;
|
||||
t.sync_type = d.sync_type;
|
||||
|
||||
t.sync_master = db->GetValue(i, 0);
|
||||
t.sync_slave = db->GetValue(i, 2);
|
||||
t.sync_rcts = db->GetValue(i, 3);
|
||||
|
||||
GenFileName(t);
|
||||
|
||||
m_list.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
db->PgClear();
|
||||
CMasterDBPool::getInstance()->ReleaseConnToPool(db);
|
||||
|
||||
if (m_list.empty())
|
||||
{
|
||||
LOG(LWAR, "Empty Sync List.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSyncList::CreateList(CReqSlaveData & d)
|
||||
{
|
||||
CSyncInfo i;
|
||||
CreateList((CReqServiceData*)&d, i);
|
||||
|
||||
i.sync_master = d.master;
|
||||
i.sync_slave = d.slave;
|
||||
|
||||
GenFileName(i);
|
||||
|
||||
m_list.push_back(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSyncList::CreateList(CReqSyncData & d)
|
||||
{
|
||||
CSyncInfo i;
|
||||
CreateList((CReqServiceData*)&d, i);
|
||||
|
||||
i.sync_master = d.master;
|
||||
i.sync_slave = d.slave;
|
||||
|
||||
GenFileName(i);
|
||||
|
||||
m_list.push_back(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CSyncInfo CSyncList::Pop()
|
||||
{
|
||||
CSyncInfo r = m_list.front();
|
||||
m_list.pop_front();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CSyncList::CreateList(const CReqServiceData * d, CSyncInfo & i)
|
||||
{
|
||||
i.start_time = d->start_time;
|
||||
i.end_time = d->end_time;
|
||||
i.sync_type = d->sync_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSyncList::GenFileName(CSyncInfo & i)
|
||||
{
|
||||
ostringstream tmp;
|
||||
//Source file
|
||||
// - diff 대상 파일
|
||||
// - source_(master)tran_id_starttime_endtime_TreadID.(master / slave)
|
||||
tmp.str("");
|
||||
tmp << SYNC_FILE_PATH << "/source_" << i.sync_master << "_" << i.sync_slave << i.sync_rcts << "_";
|
||||
tmp << i.start_time << "_" << i.end_time << "_" << pthread_self() << ".master";
|
||||
i.file_master_name = tmp.str();
|
||||
|
||||
tmp.str("");
|
||||
tmp << SYNC_FILE_PATH << "/source_" << i.sync_master << "_" << i.sync_slave << i.sync_rcts << "_";
|
||||
tmp << i.start_time << "_" << i.end_time << "_" << pthread_self() << ".slave";
|
||||
i.file_slave_name = tmp.str();
|
||||
|
||||
//Diff file
|
||||
// - Source data 비교한 결과
|
||||
// - diff_(master)tran_id_starttime_endtime_TreadID
|
||||
tmp.str("");
|
||||
tmp << SYNC_FILE_PATH << "/diff_" << i.sync_master << "_" << i.sync_slave << i.sync_rcts << "_";
|
||||
tmp << i.start_time << "_" << i.end_time << "_" << pthread_self() ;
|
||||
i.file_diff_name = tmp.str();
|
||||
|
||||
//Sync file
|
||||
//- 동기(이관) 대상 파일
|
||||
//- sync_(master)tran_id_starttime_endtime_TreadID
|
||||
tmp.str("");
|
||||
tmp << SYNC_FILE_PATH << "/sync_" << i.sync_master << "_" << i.sync_slave << i.sync_rcts << "_";
|
||||
tmp << i.start_time << "_" << i.end_time << "_" << pthread_self();
|
||||
i.file_sync_name = tmp.str();
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
Sync Information List
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SYNC_LIST_H__
|
||||
#define __SYNC_LIST_H__
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "RcSyncdRequestData.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// CSyncList 는 내부 다른 모듈에서 사용할 sync info 를 Item 으로 가지는 리스트임
|
||||
// Item 구성은 요청 받은 (RcSyncdRequestData.h 참조) 데이터로 sync info를 생성하여
|
||||
// 리스트 구성한다
|
||||
|
||||
// CSyncInfo class
|
||||
class CSyncInfo
|
||||
{
|
||||
public:
|
||||
CSyncInfo();
|
||||
~CSyncInfo();
|
||||
|
||||
public:
|
||||
// 생성된 파일 삭제 처리
|
||||
void UnlinkFile();
|
||||
|
||||
// 대소문자 구문 여부(master/slave 동일 설정이라고 가정함)
|
||||
string uri_ignore_case;
|
||||
// sync 대상 정보
|
||||
string sync_master;
|
||||
string sync_slave;
|
||||
string sync_rcts;
|
||||
|
||||
// 동기화 방식 및 추출 대상
|
||||
SYNC_TYPE::SYNC_TYPE sync_type;
|
||||
|
||||
// 동기화 구간
|
||||
string start_time;
|
||||
string end_time;
|
||||
|
||||
// 사용할 파일명
|
||||
// // Full 경로 포함. (실제 파일 존재 여부는 확인 필요)
|
||||
string file_master_name; // master source file name;
|
||||
string file_slave_name; // slave source file name(slave mode 요청도 사용)
|
||||
string file_diff_name; // diff file name
|
||||
string file_sync_name; // sync filen(sync mode 요청도 사용 )
|
||||
};
|
||||
|
||||
// CSyncInfo class
|
||||
class CSyncList
|
||||
{
|
||||
public:
|
||||
CSyncList();
|
||||
~CSyncList();
|
||||
|
||||
bool CreateList(CReqMasterData & d);
|
||||
bool CreateList(CReqSlaveData & d);
|
||||
bool CreateList(CReqSyncData & d);
|
||||
|
||||
CSyncInfo Pop();
|
||||
|
||||
inline bool Empty() { return m_list.empty(); }
|
||||
inline CSyncInfo & GetFirst() { return m_list.front(); }
|
||||
inline CSyncInfo & GetLast() { return m_list.back(); }
|
||||
|
||||
inline list<CSyncInfo>& GetList() { return m_list; }
|
||||
|
||||
private:
|
||||
void GenFileName(CSyncInfo & i);
|
||||
|
||||
bool CreateList(const CReqServiceData * d, CSyncInfo & i);
|
||||
private:
|
||||
list<CSyncInfo> m_list;
|
||||
};
|
||||
|
||||
#endif /* ___SYNC_LIST_H__*/
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "Synchronization.h"
|
||||
#include "Logger.h"
|
||||
#include "RcSyncdRequestData.h"
|
||||
#include "ProcessSocketControl.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
CSynchronization::CSynchronization(CSyncInfo &info)
|
||||
: m_syncinfo(info)
|
||||
{
|
||||
}
|
||||
|
||||
CSynchronization::~CSynchronization()
|
||||
{
|
||||
}
|
||||
|
||||
int CSynchronization::ExcuteSync()
|
||||
{
|
||||
std::string strMessage;
|
||||
std::string strErrorMessage;
|
||||
|
||||
CReqSyncData request;
|
||||
request.sync_type = m_syncinfo.sync_type;
|
||||
request.start_time = m_syncinfo.start_time;
|
||||
request.end_time = m_syncinfo.end_time;
|
||||
request.master = m_syncinfo.sync_master;
|
||||
request.slave = m_syncinfo.sync_slave;
|
||||
|
||||
// get file size
|
||||
struct stat resultFileStat;
|
||||
if( stat( m_syncinfo.file_sync_name.c_str(), &resultFileStat ) != 0 )
|
||||
{
|
||||
// 해당 파일에 대한 stat 정보 추출 실패시.
|
||||
int errorNum = errno;
|
||||
char tempBuffer[1024];
|
||||
|
||||
if( errno != ENOENT )
|
||||
{
|
||||
snprintf( tempBuffer, sizeof( tempBuffer ) - 1, "sync file mode file[%s] stat check fail [%d][%s]"
|
||||
, m_syncinfo.file_sync_name.c_str()
|
||||
, errorNum, strerror( errorNum ) );
|
||||
|
||||
strErrorMessage = tempBuffer;
|
||||
LOG( LERR, "%s", strErrorMessage.c_str() );
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 파일이 존재 하지 않는 경우는 싱크 대상 목록이 없다는 것이기 때문에 성공으로 간주한다.
|
||||
LOG( LINF, "Not exist sync file.[%s]", strErrorMessage.c_str() );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// check 모드 인 경우 단순 리턴함
|
||||
if (m_syncinfo.sync_type > SYNC_TYPE::NORMA_N_ONLY)
|
||||
return 1;
|
||||
|
||||
// 파일 size 추출.
|
||||
unsigned long long nFileSize = resultFileStat.st_size;
|
||||
|
||||
// fd open
|
||||
int resultFd = open( m_syncinfo.file_sync_name.c_str(), O_RDONLY );
|
||||
if( resultFd == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
char tempBuffer[1024];
|
||||
snprintf( tempBuffer, sizeof( tempBuffer ) - 1, "sync file mode result file[%s] open fail [%d][%s]"
|
||||
, m_syncinfo.file_sync_name.c_str()
|
||||
, errorNum, strerror( errorNum ));
|
||||
|
||||
strErrorMessage = tempBuffer;
|
||||
|
||||
LOG( LERR, "%s", strErrorMessage.c_str() );
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Slave rc_syncd 접속 및 content 정보 요청
|
||||
CProcessSocketControl slave;
|
||||
slave.ConnectTarget(m_syncinfo.sync_rcts, CServiceConfig::GetInstance()->GetOperationPort());
|
||||
|
||||
if( slave.SendRequestExecuteSyncToSlave( request, resultFd, nFileSize, strMessage ) == false )
|
||||
{
|
||||
// 전송 실패시
|
||||
_LOG( LERR, "%s", strMessage.c_str());
|
||||
close(resultFd);
|
||||
slave.Close();
|
||||
return -3;
|
||||
}
|
||||
_LOG( LDBG, "%s", strMessage.c_str());
|
||||
close(resultFd);
|
||||
slave.Close();
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/****************************************************************************
|
||||
Synchronization Class Header
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __SYNCHRONIZATION_H__
|
||||
#define __SYNCHRONIZATION_H__
|
||||
|
||||
#include "SyncList.h"
|
||||
|
||||
class CSynchronization
|
||||
{
|
||||
public:
|
||||
CSynchronization(CSyncInfo &info);
|
||||
~CSynchronization();
|
||||
|
||||
// sync ±¸µ¿ ¿äû
|
||||
int ExcuteSync();
|
||||
|
||||
private:
|
||||
CSyncInfo m_syncinfo;
|
||||
};
|
||||
|
||||
#endif /* __SYNCHRONIZATION_H__ */
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "Util.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#define SEC_TO_MICROSEC (1000000LL)
|
||||
|
||||
|
||||
/// @brief 현재 시간 정보를 micro-second 단위로 계산하여 반환
|
||||
/// @return 1970년 1월 1일 이후부터의 현재시간을 micro-second(1/1,000,000) 단위로 반환처리, 오류발생시에는 -1 값을 반환.
|
||||
long long longtime_now()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if( gettimeofday(&tv, NULL) == 0 )
|
||||
{
|
||||
// 성공시 micro-second 단위의 값을 반환
|
||||
return tv.tv_sec * SEC_TO_MICROSEC + tv.tv_usec;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 실패시 -1 값을 반환.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief source string에 주어진 search string을 replacement로 변환 화여 반환
|
||||
std::string stringreplace(const std::string& source, const std::string search, const std::string replacement)
|
||||
{
|
||||
std::string r = source;
|
||||
|
||||
std::string::size_type pos = 0;
|
||||
|
||||
while ( (pos = r.find(search, pos)) != std::string::npos )
|
||||
{
|
||||
r.replace( pos, search.size(), replacement );
|
||||
pos = pos + replacement.size();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string strtime_now()
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm * timeinfo;
|
||||
char buffer[16] = { 0 };
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
if (strftime(buffer, sizeof buffer, "%Y%m%d%H%M%S", timeinfo) <= 0)
|
||||
return "";
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
time_t str2time_t(std::string strtime)
|
||||
{
|
||||
struct tm tm = { 0 };
|
||||
|
||||
if (strtime == "0")
|
||||
return 0;
|
||||
|
||||
if (strptime(strtime.c_str(), "%Y%m%d%H%M%S", &tm) == NULL)
|
||||
return -1;
|
||||
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
||||
std::string time_t2string(time_t rawtime)
|
||||
{
|
||||
struct tm * timeinfo;
|
||||
char buffer[16] = { 0 };
|
||||
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
if (strftime(buffer, sizeof buffer, "%Y%m%d%H%M%S", timeinfo) <= 0)
|
||||
return "";
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
long long str2longtime(std::string strtime)
|
||||
{
|
||||
return str2time_t(strtime) * SEC_TO_MICROSEC;
|
||||
}
|
||||
|
||||
void StringSplit(std::string str, std::string delim, std::vector<std::string> &results, bool bUseEmpty /*= false*/)
|
||||
{
|
||||
const std::string strEmpty("");
|
||||
std::string::size_type cutAt;
|
||||
|
||||
while ((cutAt = str.find_first_of(delim)) != str.npos)
|
||||
{
|
||||
if (cutAt > 0)
|
||||
{
|
||||
results.push_back(str.substr(0, cutAt));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bUseEmpty && cutAt == 0)
|
||||
results.push_back(strEmpty);
|
||||
}
|
||||
str = str.substr(cutAt + 1);
|
||||
}
|
||||
if (str.length() > 0)
|
||||
{
|
||||
results.push_back(str);
|
||||
}
|
||||
}
|
||||
|
||||
void solusleep(unsigned long usec)
|
||||
{
|
||||
// usleep 사용시 multi thread 환경에서 block 발생 가능성이 존재
|
||||
// 이에 nanosleep 함수를 사용토록 수정 처리함.
|
||||
struct timespec sleep;
|
||||
|
||||
if (usec >= 1000000)
|
||||
{
|
||||
sleep.tv_sec = (int)(usec / 1000000);
|
||||
sleep.tv_nsec = (usec - ((long)sleep.tv_sec * 1000000)) * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = usec * 1000;
|
||||
}
|
||||
|
||||
nanosleep(&sleep, NULL);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/***************************************************************************
|
||||
Util functions
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : storage dev team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __UTIL_H__
|
||||
#define __UTIL_H__
|
||||
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/// @brief 현재 시간 정보를 micro-second 단위로 계산하여 반환.
|
||||
/// @return 1970년 1월 1일 이후부터의 현재시간을 micro-second(1/1,000,000) 단위로 반환처리, 오류발생시에는 -1 값을 반환.
|
||||
long long longtime_now(void);
|
||||
|
||||
/// @brief source string에 주어진 search string을 replacement로 변환 하여 결과 반환.
|
||||
std::string stringreplace(const std::string& source, const std::string search, const std::string replacement);
|
||||
|
||||
// string now time
|
||||
std::string strtime_now();
|
||||
|
||||
// time_t to stirng
|
||||
std::string time_t2string(time_t rawtime);
|
||||
|
||||
// string to time_t
|
||||
time_t str2time_t(std::string strtime);
|
||||
|
||||
// string to microsecond
|
||||
long long str2longtime(std::string strtime);
|
||||
|
||||
// Split string function
|
||||
// bUseEmpty값이 true면 delimiter의 갯수에 따라 results.size()의 숫자도 맞추기 위한 옵션
|
||||
void StringSplit(std::string str, std::string delim, std::vector<std::string> &results, bool bUseEmpty = false);
|
||||
|
||||
void solusleep(unsigned long usec);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif // __UTIL_H__
|
||||
@@ -0,0 +1,548 @@
|
||||
#include "Validation.h"
|
||||
#include "DataFile.h"
|
||||
#include "DBConnPool.h"
|
||||
#include "Database.h"
|
||||
#include "Util.h"
|
||||
#include "Logger.h"
|
||||
#include "ReportLog.h"
|
||||
#include "ServiceConfig.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FLAG_SYNC "SYNC"
|
||||
#define FLAG_DEL "DEL"
|
||||
#define FLAG_NSYNC "NSYNC"
|
||||
#define FLAG_COPY "COPY"
|
||||
#define FLAG_MOVE "MOVE"
|
||||
|
||||
// uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn
|
||||
class DIFFFILE_FIELD
|
||||
{
|
||||
public:
|
||||
enum FIELD
|
||||
{
|
||||
uri = 0, filename_hash, resource_type, get_content_length,
|
||||
file_lastmodified, deleted_yn,
|
||||
MAX_FILED
|
||||
};
|
||||
};
|
||||
|
||||
// meta table filed
|
||||
class CURRENT_FIELD
|
||||
{
|
||||
public:
|
||||
enum FIELD
|
||||
{
|
||||
uri = 0, filename_hash, host_name, resource_type,
|
||||
depth, creation_date, display_name,
|
||||
get_content_length, get_content_type,
|
||||
get_lastmodified, source, deleted_yn,
|
||||
is_cache, file_lastmodified,
|
||||
MAX_FILED
|
||||
};
|
||||
};
|
||||
|
||||
// flag|uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|host_name|creation_date|get_content_type|src_uri|slave_tran_id
|
||||
class SYNCFILE_FIELD
|
||||
{
|
||||
public:
|
||||
// SYNCFILE_FIELD::flag
|
||||
// - SYCN : 동기화 필요
|
||||
// - DEL : 삭제 필요
|
||||
// - COPY : 복사된 파일임
|
||||
// - MOVE : 이동된 파일임
|
||||
|
||||
enum FIELD
|
||||
{
|
||||
flag = 0, uri, filename_hash, resource_type, get_content_length,
|
||||
file_lastmodified, deleted_yn, host_name, creation_date, get_content_type,
|
||||
src_uri, slave_tran_id, uri_ignore_case,
|
||||
// copy 속성을 찾기 위해서 추가(sync file 경우 filename_hash 필드에 해당 값 사용)
|
||||
src_filename_hash,
|
||||
MAX_FILED
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
static int StringCount(string str, string delim)
|
||||
{
|
||||
int nCount = 0;
|
||||
string::size_type cutAt;
|
||||
|
||||
while ((cutAt = str.find_first_of(delim)) != str.npos)
|
||||
{
|
||||
if (cutAt > 0)
|
||||
{
|
||||
nCount++;
|
||||
}
|
||||
str = str.substr(cutAt + 1);
|
||||
}
|
||||
if (str.length() > 0)
|
||||
nCount++;
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
CValidation::CValidation(CSyncInfo& info, string data)
|
||||
: m_syncinfo(info), m_diffdata(data)
|
||||
{
|
||||
}
|
||||
|
||||
CValidation::~CValidation()
|
||||
{
|
||||
}
|
||||
|
||||
bool CValidation::CheckValidation(bool is_master /*= true*/)
|
||||
{
|
||||
CMasterDBPool* pool = CMasterDBPool::getInstance();
|
||||
|
||||
if (pool == NULL)
|
||||
{
|
||||
LOG(LERR, "DB Coon Pool is NULL");
|
||||
return false;
|
||||
}
|
||||
|
||||
// uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn
|
||||
vector<string> vectdiff;
|
||||
StringSplit(m_diffdata, "|", vectdiff, true);
|
||||
if (vectdiff.size() != DIFFFILE_FIELD::MAX_FILED)
|
||||
{
|
||||
LOG(LERR, "validation sync file string split caution :[%s]", m_diffdata.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
DataBase *db = pool->GetConnFromPool();
|
||||
|
||||
if (!db)
|
||||
{
|
||||
LOG(LERR, "Failed GetDB.");
|
||||
return false;
|
||||
}
|
||||
|
||||
string tran_id = (is_master ? m_syncinfo.sync_master : m_syncinfo.sync_slave);
|
||||
string tblname = pool->GetMetaTableName(tran_id.c_str());
|
||||
bool useDisyplay = pool->UseDisplayname();
|
||||
|
||||
// check 1 : diffdata에 대한 RCDB 최신 상태 비교
|
||||
|
||||
/// Get Current Meta
|
||||
if (GetCurrentMeta(db, vectdiff, tblname, tran_id, useDisyplay) == false)
|
||||
{
|
||||
pool->ReleaseConnToPool(db, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Compare input & current
|
||||
vector<string>vectOut = CompareData(vectdiff, tran_id);
|
||||
if (vectOut.empty())
|
||||
{
|
||||
pool->ReleaseConnToPool(db);
|
||||
LOG(LERR, "Failed CompareData.[%s]", m_diffdata.c_str())
|
||||
return false;
|
||||
}
|
||||
|
||||
// write sync file formate
|
||||
if (WriteSyncFile(vectOut) == false)
|
||||
{
|
||||
pool->ReleaseConnToPool(db);
|
||||
LOG(LERR, "Failed Write Sync File.[%s]", m_diffdata.c_str())
|
||||
return false;
|
||||
}
|
||||
|
||||
pool->ReleaseConnToPool(db);
|
||||
|
||||
return true;
|
||||
}
|
||||
string CValidation::GetFullFilenameHash(vector<string> & vectdiff, string &tran_id)
|
||||
{
|
||||
string r;
|
||||
|
||||
std::vector<std::string> vecMount = CServiceConfig::GetInstance()->GetFHSMount();
|
||||
|
||||
for (vector<string>::size_type i = 0; i < vecMount.size(); ++i)
|
||||
{
|
||||
string hash = "/" + tran_id + vectdiff[DIFFFILE_FIELD::filename_hash];
|
||||
if (i > 0)
|
||||
r += ",";
|
||||
r += vecMount[i] + hash;
|
||||
}
|
||||
|
||||
// 2014.06.07 dadamin
|
||||
// ANY 함수 사용을 {} 포함된 경우 array 로 인되는 경우 방지
|
||||
r = stringreplace(r, "{", "\\{");
|
||||
r = stringreplace(r, "}", "\\}");
|
||||
|
||||
r = "{" + r + "}";
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CValidation::GetCurrentMeta(DataBase* d, vector<string> & vectdiff, string &tblname, string &tran_id, bool useDisyplay)
|
||||
{
|
||||
ostringstream sql;
|
||||
|
||||
ostringstream t;
|
||||
const char *paramValues[5];
|
||||
|
||||
int index = 0;
|
||||
|
||||
// check 1 : diffdata에 대한 RCDB 최신 상태
|
||||
sql << "SELECT ";
|
||||
// 메타 변경에 다른 참조할 uri 컬럼 값이 다름
|
||||
// 기존 uri 동일한 값은 display_name 임
|
||||
if (useDisyplay)
|
||||
sql << "display_name,";
|
||||
else
|
||||
sql << "uri,";
|
||||
sql << "filename_hash, host_name, resource_type, ";
|
||||
sql << "depth, creation_date, display_name, ";
|
||||
sql << "get_content_length, get_content_type, ";
|
||||
sql << "get_lastmodified, source, deleted_yn, ";
|
||||
sql << "is_cache, file_lastmodified ";
|
||||
|
||||
sql << "FROM " << tblname << " ";
|
||||
|
||||
sql << "WHERE ";
|
||||
|
||||
string strdepth, strfulluri, strfullhash;
|
||||
if (vectdiff[DIFFFILE_FIELD::resource_type] == "0")
|
||||
{
|
||||
// file
|
||||
sql << "filename_hash = ANY ($1) ";
|
||||
sql << "AND resource_type = $2 ";
|
||||
sql << "AND get_content_length = $3 ";
|
||||
|
||||
strfullhash = GetFullFilenameHash(vectdiff, tran_id);
|
||||
// filename_hash
|
||||
paramValues[0] = strfullhash.c_str();
|
||||
// resource_type
|
||||
paramValues[1] = vectdiff[DIFFFILE_FIELD::resource_type].c_str();
|
||||
// get_content_length
|
||||
paramValues[2] = vectdiff[DIFFFILE_FIELD::get_content_length].c_str();
|
||||
|
||||
index = 3;
|
||||
|
||||
LOG(LDBG, "Value [Get Current Info(file)] => %s,%s,%s",
|
||||
paramValues[0], paramValues[1], paramValues[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
sql << "depth = $1 ";
|
||||
|
||||
if (useDisyplay && m_syncinfo.uri_ignore_case == "Y")
|
||||
{
|
||||
sql << "AND uri = lower($2) ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql << "AND uri = $2 ";
|
||||
}
|
||||
|
||||
// dir
|
||||
sql << "AND resource_type = $3 ";
|
||||
sql << "AND get_content_length = $4 ";
|
||||
|
||||
// depth 값 구하기.
|
||||
int nDEPTH = StringCount(vectdiff[DIFFFILE_FIELD::uri], "/");
|
||||
t << nDEPTH;
|
||||
|
||||
strdepth = t.str(); t.str("");
|
||||
|
||||
// Full URI
|
||||
strfulluri = "/" + tran_id + vectdiff[DIFFFILE_FIELD::uri];
|
||||
|
||||
// depth
|
||||
paramValues[0] = strdepth.c_str();
|
||||
// uri
|
||||
paramValues[1] = strfulluri.c_str();
|
||||
// resource_type
|
||||
paramValues[2] = vectdiff[DIFFFILE_FIELD::resource_type].c_str();
|
||||
// get_content_length
|
||||
paramValues[3] = vectdiff[DIFFFILE_FIELD::get_content_length].c_str();
|
||||
|
||||
index = 4;
|
||||
|
||||
LOG(LDBG, "Value [Get Current Info(dir)] => %s,%s,%s,%s",
|
||||
paramValues[0], paramValues[1], paramValues[2], paramValues[3]);
|
||||
}
|
||||
|
||||
sql << "AND deleted_yn = 'N' AND is_cache = 'N';";
|
||||
|
||||
LOG(LDBG, "SQL[Get Current Info] => %s", sql.str().c_str());
|
||||
|
||||
d->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);
|
||||
|
||||
// Query 결과를 가져온다.
|
||||
if (d->PgResult(DataBase::NOT_CLEAR) < 0)
|
||||
{
|
||||
LOG(LERR, "RCDB Meta failed.[%s][%s]",
|
||||
vectdiff[DIFFFILE_FIELD::uri].c_str(), d->GetErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < d->GetNoTuples(); ++i)
|
||||
{
|
||||
vector<string> vectcurr(CURRENT_FIELD::MAX_FILED);
|
||||
|
||||
string struri = d->GetValue(i, CURRENT_FIELD::uri);
|
||||
|
||||
size_t found = struri.find_first_of("/", 1);
|
||||
if (found != string::npos)
|
||||
{
|
||||
vectcurr[CURRENT_FIELD::uri] = struri.substr(found);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LNOT, "Use the uri as in RCDB.[%s]", struri.c_str());
|
||||
vectcurr[CURRENT_FIELD::uri] = struri;
|
||||
}
|
||||
|
||||
if (vectdiff[DIFFFILE_FIELD::resource_type] == "0")
|
||||
vectcurr[CURRENT_FIELD::filename_hash] = d->GetValue(i, CURRENT_FIELD::filename_hash);
|
||||
|
||||
vectcurr[CURRENT_FIELD::host_name] = d->GetValue(i, CURRENT_FIELD::host_name);
|
||||
vectcurr[CURRENT_FIELD::resource_type] = d->GetValue(i, CURRENT_FIELD::resource_type);
|
||||
vectcurr[CURRENT_FIELD::depth] = d->GetValue(i, CURRENT_FIELD::depth);
|
||||
vectcurr[CURRENT_FIELD::creation_date] = d->GetValue(i, CURRENT_FIELD::creation_date);
|
||||
vectcurr[CURRENT_FIELD::display_name] = d->GetValue(i, CURRENT_FIELD::display_name);
|
||||
vectcurr[CURRENT_FIELD::get_content_length] = d->GetValue(i, CURRENT_FIELD::get_content_length);
|
||||
vectcurr[CURRENT_FIELD::get_content_type] = d->GetValue(i, CURRENT_FIELD::get_content_type);
|
||||
vectcurr[CURRENT_FIELD::get_lastmodified] = d->GetValue(i, CURRENT_FIELD::get_lastmodified);
|
||||
vectcurr[CURRENT_FIELD::source] = d->GetValue(i, CURRENT_FIELD::source);
|
||||
vectcurr[CURRENT_FIELD::deleted_yn] = d->GetValue(i, CURRENT_FIELD::deleted_yn);
|
||||
vectcurr[CURRENT_FIELD::is_cache] = d->GetValue(i, CURRENT_FIELD::is_cache);
|
||||
vectcurr[CURRENT_FIELD::file_lastmodified] = d->GetValue(i, CURRENT_FIELD::file_lastmodified);
|
||||
|
||||
m_current.insert(CCurretMap::value_type(struri, vectcurr));
|
||||
}
|
||||
|
||||
d->PgClear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<string> CValidation::CompareData(vector<string> & vectdiff, string &tran_id)
|
||||
{
|
||||
// flag|uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|host_name|src_uri|slave tran_id
|
||||
vector<string> r(SYNCFILE_FIELD::MAX_FILED);
|
||||
|
||||
r[SYNCFILE_FIELD::uri] = vectdiff[DIFFFILE_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::filename_hash] = vectdiff[DIFFFILE_FIELD::filename_hash];
|
||||
|
||||
r[SYNCFILE_FIELD::resource_type] = vectdiff[DIFFFILE_FIELD::resource_type];
|
||||
r[SYNCFILE_FIELD::get_content_length] = vectdiff[DIFFFILE_FIELD::get_content_length];
|
||||
r[SYNCFILE_FIELD::file_lastmodified] = vectdiff[DIFFFILE_FIELD::file_lastmodified];
|
||||
r[SYNCFILE_FIELD::deleted_yn] = vectdiff[DIFFFILE_FIELD::deleted_yn];
|
||||
|
||||
r[SYNCFILE_FIELD::slave_tran_id] = m_syncinfo.sync_slave;
|
||||
r[SYNCFILE_FIELD::uri_ignore_case] = m_syncinfo.uri_ignore_case;
|
||||
do
|
||||
{
|
||||
if (m_current.empty())
|
||||
{
|
||||
// m_diffdata에 포함된 uir, filename_hash 해당 하는 값이 존재 하지 않으므로 삭제 처리
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_DEL;
|
||||
break;
|
||||
}
|
||||
|
||||
string struri = "/" + tran_id + vectdiff[DIFFFILE_FIELD::uri];
|
||||
int eqcnt = m_current.count(struri);
|
||||
|
||||
if (eqcnt > 1)
|
||||
{
|
||||
// 디렉토리 경우 생성함
|
||||
if (vectdiff[DIFFFILE_FIELD::resource_type] == "1")
|
||||
{
|
||||
CCurretMap::iterator curr = m_current.find(struri);
|
||||
|
||||
r[SYNCFILE_FIELD::creation_date] = (*curr).second[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::file_lastmodified] = (*curr).second[CURRENT_FIELD::file_lastmodified];
|
||||
r[SYNCFILE_FIELD::get_content_type] = (*curr).second[CURRENT_FIELD::get_content_type];
|
||||
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_NSYNC;
|
||||
break;
|
||||
}
|
||||
|
||||
// 해당 파일 싱크 하지 않음(report log 기록)
|
||||
CReportLog rlog;
|
||||
|
||||
if (rlog.Init(CServiceConfig::GetInstance()->GetLogPath()))
|
||||
{
|
||||
rlog.Write("WAR", "[%s] [The duplicate files.[uri :%s]]", PROG_NAME, struri.c_str());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// diff된 uri == RCDB : 1개
|
||||
if (eqcnt == 1 )
|
||||
{
|
||||
if (m_current.size() == 1)
|
||||
{
|
||||
CCurretMap::iterator curr = m_current.find(struri);
|
||||
|
||||
r[SYNCFILE_FIELD::creation_date] = (*curr).second[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::get_content_type] = (*curr).second[CURRENT_FIELD::get_content_type];
|
||||
r[SYNCFILE_FIELD::file_lastmodified] = (*curr).second[CURRENT_FIELD::file_lastmodified];
|
||||
|
||||
if ((*curr).second[CURRENT_FIELD::resource_type] == "1" ||
|
||||
(*curr).second[CURRENT_FIELD::file_lastmodified] != vectdiff[DIFFFILE_FIELD::file_lastmodified])
|
||||
{
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_NSYNC;
|
||||
break;
|
||||
}
|
||||
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
r[SYNCFILE_FIELD::host_name] = (*curr).second[CURRENT_FIELD::host_name];
|
||||
|
||||
//r[SYNCFILE_FIELD::src_uri] = current[CURR_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::src_filename_hash] = (*curr).second[CURRENT_FIELD::filename_hash];
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy
|
||||
vector<string> src, self;
|
||||
int64_t o = 0, n = 0;
|
||||
|
||||
CCurretMap::iterator i = m_current.begin();
|
||||
|
||||
while (i != m_current.end()) // Loop until end is reached.
|
||||
{
|
||||
//cout << (*i).first << " -> " << (*i).second << "\n";
|
||||
|
||||
if ((*i).first != struri)
|
||||
{
|
||||
// get_lastmodified 작은 값을 원본 소스 취급
|
||||
n = convert((*i).second[CURRENT_FIELD::get_lastmodified]);
|
||||
if (o > n || o == 0)
|
||||
{
|
||||
o = n;
|
||||
src = (*i).second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self = (*i).second;;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (src.empty())
|
||||
{
|
||||
CReportLog rlog;
|
||||
|
||||
if (rlog.Init(CServiceConfig::GetInstance()->GetLogPath()))
|
||||
{
|
||||
rlog.Write("WAR", "[%s] [Not Found Source File.[uri :?? => %s]]", PROG_NAME, struri.c_str());
|
||||
}
|
||||
r.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
if (n < convert(self[CURRENT_FIELD::get_lastmodified]))
|
||||
{
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_COPY;
|
||||
r[SYNCFILE_FIELD::src_uri] = src[CURRENT_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::host_name] = src[CURRENT_FIELD::host_name];
|
||||
r[SYNCFILE_FIELD::src_filename_hash] = src[CURRENT_FIELD::filename_hash];
|
||||
|
||||
r[SYNCFILE_FIELD::creation_date] = self[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::get_content_type] = self[CURRENT_FIELD::get_content_type];
|
||||
}
|
||||
else
|
||||
{
|
||||
//r.clear();
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_COPY;
|
||||
r[SYNCFILE_FIELD::host_name] = src[CURRENT_FIELD::host_name];
|
||||
r[SYNCFILE_FIELD::src_filename_hash] = src[CURRENT_FIELD::filename_hash];
|
||||
|
||||
r[SYNCFILE_FIELD::creation_date] = self[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::get_content_type] = self[CURRENT_FIELD::get_content_type];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (eqcnt == 0)
|
||||
{
|
||||
// move
|
||||
|
||||
vector<string> dest;
|
||||
CCurretMap::iterator i = m_current.begin();
|
||||
if (m_current.size() == 1)
|
||||
{
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_MOVE;
|
||||
dest = (*i).second;
|
||||
|
||||
r[SYNCFILE_FIELD::src_uri] = r[SYNCFILE_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::uri] = dest[CURRENT_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::host_name] = dest[CURRENT_FIELD::host_name];
|
||||
r[SYNCFILE_FIELD::file_lastmodified] = dest[CURRENT_FIELD::file_lastmodified];
|
||||
r[SYNCFILE_FIELD::src_filename_hash] = dest[CURRENT_FIELD::filename_hash];
|
||||
|
||||
r[SYNCFILE_FIELD::creation_date] = dest[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::get_content_type] = dest[CURRENT_FIELD::get_content_type];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2개 이상 존재 어떤 것으로 이동된지 알수 없으므로 해당 파일 삭제 처리
|
||||
r[SYNCFILE_FIELD::flag] = FLAG_DEL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CValidation::WriteSyncFile(vector<string>& outdata)
|
||||
{
|
||||
// flag|uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|host_name|creation_date|get_content_type|src_uri|slave_tran_id|uri_ignore_case
|
||||
CDataFile syncfile;
|
||||
syncfile.Init(m_syncinfo.file_sync_name.c_str(), false);
|
||||
|
||||
vector<string>::size_type n = SYNCFILE_FIELD::MAX_FILED - (SYNCFILE_FIELD::MAX_FILED - SYNCFILE_FIELD::src_filename_hash);
|
||||
|
||||
string w;
|
||||
for (vector<string>::size_type i = 0; i < n; ++i)
|
||||
{
|
||||
if (i> 0)
|
||||
w += "|";
|
||||
|
||||
if( i == SYNCFILE_FIELD::filename_hash)
|
||||
{
|
||||
if (outdata[SYNCFILE_FIELD::src_filename_hash].size())
|
||||
{
|
||||
w += outdata[SYNCFILE_FIELD::src_filename_hash];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
w += outdata[i];
|
||||
}
|
||||
|
||||
bool r = syncfile.Write("%s", w.c_str());
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
Validation Class
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __VALIDATION_H__
|
||||
#define __VALIDATION_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
# if __GNUC__ >= 3
|
||||
# include <ext/hash_map>
|
||||
using namespace __gnu_cxx;
|
||||
# else
|
||||
# include <hash_map>
|
||||
# endif
|
||||
|
||||
#include "SyncList.h"
|
||||
#include "Database.h"
|
||||
|
||||
struct hash_key2
|
||||
{
|
||||
size_t operator() (const string &k) const
|
||||
{
|
||||
return __stl_hash_string(k.c_str());
|
||||
}
|
||||
};
|
||||
struct compare_key2
|
||||
{
|
||||
bool operator () (const string s1, const string &s2) const
|
||||
{
|
||||
return s1 == s2;
|
||||
}
|
||||
};
|
||||
|
||||
typedef hash_multimap<string, vector<string>, hash_key2, compare_key2> CCurretMap;
|
||||
|
||||
class CValidation
|
||||
{
|
||||
public:
|
||||
CValidation(CSyncInfo& info, string data);
|
||||
~CValidation();
|
||||
|
||||
// diff 된 데이터 검증
|
||||
bool CheckValidation(bool is_master = true);
|
||||
|
||||
private:
|
||||
// 현재 meta에서 input된 uri, hash에 대한 최신 상태 가져오기
|
||||
bool GetCurrentMeta(DataBase* db, vector<string> & vectdiff, string &tblname, string &tran_id, bool useDisyplay);
|
||||
|
||||
// input 된 데이터와 현재 meta 데이터 비교
|
||||
// sync file로 저장될 데이터를 리턴한다.
|
||||
vector<string> CompareData(vector<string> & vectdiff, string &tran_id);
|
||||
|
||||
// outdata 를 sync file formate 맞게 쓰기함
|
||||
bool WriteSyncFile(vector<string>& outdata);
|
||||
|
||||
// filename_hash 리턴
|
||||
string GetFullFilenameHash(vector<string> & vectdiff, string &tran_id);
|
||||
|
||||
CSyncInfo m_syncinfo;
|
||||
string m_diffdata;
|
||||
|
||||
CCurretMap m_current;
|
||||
};
|
||||
|
||||
#endif /* __VALIDATION_H__ */
|
||||
@@ -0,0 +1,470 @@
|
||||
/***************************************************************************
|
||||
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 <unistd.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
|
||||
#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<CWork *>(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_master.m_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<CWork *, short>(w, CWorkPool::NOTWORK));
|
||||
}
|
||||
|
||||
if( m_pool.size() < static_cast<unsigned int>(poolcnt) )
|
||||
{
|
||||
DestroyPool();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CWorkPool::DestroyPool()
|
||||
{
|
||||
map<CWork*, short>::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<CWork *>(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<CWork*, short>::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<CWork*, short>::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<CWork*, short>::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<CWork*, short>::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<string> 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;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/***************************************************************************
|
||||
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.
|
||||
***************************************************************************/
|
||||
#ifndef __WORK_POOL_H__
|
||||
#define __WORK_POOL_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
# if __GNUC__ >= 3
|
||||
# include <ext/hash_map>
|
||||
using namespace __gnu_cxx;
|
||||
# else
|
||||
# include <hash_map>
|
||||
# endif
|
||||
|
||||
typedef int (*work_notifyfn)(void *object, short success);
|
||||
|
||||
struct hash_key
|
||||
{
|
||||
size_t operator() (const string &k) const
|
||||
{
|
||||
return __stl_hash_string(k.c_str());
|
||||
}
|
||||
};
|
||||
struct compare_key
|
||||
{
|
||||
bool operator () (const string s1, const string &s2) const
|
||||
{
|
||||
return s1 == s2;
|
||||
}
|
||||
};
|
||||
|
||||
typedef hash_map<string, short, hash_key, compare_key> workurimap;
|
||||
|
||||
#include "SyncList.h"
|
||||
|
||||
class CWork
|
||||
{
|
||||
public:
|
||||
CWork();
|
||||
~CWork();
|
||||
|
||||
bool init();
|
||||
bool run(CSyncInfo info, string rundata, work_notifyfn nofi = NULL, void * parm = NULL);
|
||||
|
||||
void setexit(bool v);
|
||||
void setenablesync(const char* szOn) {m_enablesync = szOn;}
|
||||
|
||||
pthread_t* getworkhandle() {return &m_thread;}
|
||||
|
||||
const char* getrundata() { return m_rundata.c_str(); }
|
||||
int getsetp() { return m_step; }
|
||||
private:
|
||||
static void* working(void * pdata);
|
||||
|
||||
private:
|
||||
int m_step;
|
||||
bool m_exit;
|
||||
string m_rundata;
|
||||
|
||||
CSyncInfo m_syncinfo;
|
||||
|
||||
string m_workuri;
|
||||
work_notifyfn m_nofi;
|
||||
void* m_parm;
|
||||
string m_enablesync;
|
||||
|
||||
pthread_t m_thread;
|
||||
pthread_cond_t m_workcond;
|
||||
pthread_mutex_t m_workmutex;
|
||||
};
|
||||
|
||||
class CWorkPool
|
||||
{
|
||||
public:
|
||||
enum WORK_SATAUSE
|
||||
{
|
||||
WORKING = 0,
|
||||
NOTWORK = 1
|
||||
};
|
||||
|
||||
public:
|
||||
static void init();
|
||||
static CWorkPool* getInstance();
|
||||
static void release();
|
||||
|
||||
int CreatePool( int poolcnt = 10 );
|
||||
int DestroyPool();
|
||||
|
||||
bool addworkuri(string tranid, string uri, string &workuri,
|
||||
bool sourcedata = false, int timeout = 5);
|
||||
bool delworkuri(string key);
|
||||
|
||||
void printstatus(string prefixed = "");
|
||||
void printstatusex(string prefixed = "");
|
||||
|
||||
CWork* GetWorkPool(int timeout = 0);
|
||||
void ReleaseWork(CWork *w);
|
||||
|
||||
private:
|
||||
CWorkPool();
|
||||
~CWorkPool();
|
||||
|
||||
private:
|
||||
static CWorkPool* m_inst;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_mutex_t m_mutexuri;
|
||||
pthread_mutex_t m_mutextry;
|
||||
|
||||
workurimap m_workurimap;
|
||||
map<CWork*, short> m_pool;
|
||||
};
|
||||
|
||||
#endif // __WORK_POOL_H__
|
||||
@@ -0,0 +1,211 @@
|
||||
#include "Worker.h"
|
||||
|
||||
#include "ProcessRename.h"
|
||||
#include "ServiceConfig.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include "ProcessStatus.h"
|
||||
#include "Running.h"
|
||||
#include "Scheduler.h"
|
||||
#include "WorkPool.h"
|
||||
#include "DBConnPool.h"
|
||||
#include "ClientThread.h"
|
||||
#include "Util.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// Worker Process 의 main 함수
|
||||
int WorkerMain( int listenSocket )
|
||||
{
|
||||
// Process Rename
|
||||
set_ps_display(PROG_NAME": Worker [initialize process]", false);
|
||||
|
||||
// Set Signal Handler
|
||||
SetSignalWorker();
|
||||
|
||||
// 로그 출력 순서가 Main 프로세스와 꼬일 수 있어... 1초간 대기 후 진행
|
||||
sleep( 1 );
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 1. 각 모듈 생성 및 초기화.
|
||||
// - 초기화 실패시 EXIT_FAILURE 를 return 하여 프로세스가 종료되도록 한다.
|
||||
|
||||
// 1.1 Run List 생성
|
||||
// 스케줄링을 통해서 실행 시 시간 중복 구간을 방지 위해서 실행 중인 작업을 list로 관리하고 있음
|
||||
CRunlist::init();
|
||||
|
||||
// 1.2 스케줄링 생성 및 구동
|
||||
CScheduler scheduler;
|
||||
scheduler.addtask(CScheduler::TIME_INTERVAL, CServiceConfig::GetInstance()->GetChkSmall());
|
||||
scheduler.addtask(CScheduler::TIME_INTERVAL, CServiceConfig::GetInstance()->GetChkMiddle());
|
||||
scheduler.addtask(CScheduler::TIME_ONCE, CServiceConfig::GetInstance()->GetChkOnce());
|
||||
if (scheduler.run() != 0)
|
||||
{
|
||||
LOG( LERR, "Worker[%d] scheduler module run() failed.", getpid() );
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지
|
||||
}
|
||||
|
||||
// 1.3 Work Pool 생성
|
||||
if( CWorkPool::getInstance()->CreatePool( CServiceConfig::GetInstance()->GetWorkPoolCount() ) != 0 )
|
||||
{
|
||||
LOG(LERR, "Worker[%d] Work Pool Create() failed.", getpid());
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지
|
||||
}
|
||||
|
||||
// 1.4 DB Connection Pool 생성
|
||||
CDataBaseInfo info;
|
||||
info.m_hostaddr = CServiceConfig::GetInstance()->GetRcdbIp();
|
||||
info.m_port = CServiceConfig::GetInstance()->GetRcdbPort();
|
||||
info.m_dbname = CServiceConfig::GetInstance()->GetRcdbName();
|
||||
info.m_user = CServiceConfig::GetInstance()->GetRcdbAcct();
|
||||
info.m_pw = CServiceConfig::GetInstance()->GetRcdbAcctPw();
|
||||
|
||||
CMasterDBPool::init(info);
|
||||
if (CMasterDBPool::getInstance()->CreatePool(CServiceConfig::GetInstance()->GetDbPoolCount()) <= 0)
|
||||
{
|
||||
LOG(LERR, "Worker[%d] DB Connection Pool module Create() failed.", getpid());
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지
|
||||
}
|
||||
_LOG( LINF, "Worker[%d]: CMasterDBPool module start.", getpid() );
|
||||
|
||||
// 1.5 Process status 모듈 생성 및 기동
|
||||
CProcessStatus processStatus;
|
||||
if( processStatus.Start() == false )
|
||||
{
|
||||
LOG( LERR, "Worker[%d]: Process status module start fail. => Worker Exit", getpid() );
|
||||
return EXIT_FAILURE; // EXIT_FAILURE 를 반환하여 재생성 처리 방지
|
||||
}
|
||||
_LOG( LINF, "Worker[%d]: CProcessStatus module start.", getpid() );
|
||||
|
||||
|
||||
|
||||
// 모듈 초기화 및 기동 처리 완료.
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Worker 프로세스의 작업 수행.
|
||||
|
||||
// Listen Socket 에 대한 Accept 대기 수행
|
||||
int clientSocket;
|
||||
struct sockaddr_in clientSockAddr;
|
||||
socklen_t clientSockLen = sizeof( clientSockAddr );
|
||||
char szClientIp[INET_ADDRSTRLEN];
|
||||
|
||||
CClientThread * pClientThread;
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
clientSocket = accept( listenSocket, ( struct sockaddr * ) &clientSockAddr, &clientSockLen );
|
||||
if( clientSocket == -1 )
|
||||
{
|
||||
// 오류발생시 해당 내역 로깅처리.
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "Worker: client accept failed. [%d][%s]", errorNum, strerror( errorNum ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상적인 Client 인 경우...
|
||||
memset( szClientIp, 0x00, sizeof( szClientIp ) );
|
||||
if( inet_ntop( AF_INET, &( clientSockAddr.sin_addr ), szClientIp, sizeof( szClientIp ) ) == NULL )
|
||||
{
|
||||
// 변환 실패시.. 0.0.0.0 으로 설정 처리.
|
||||
snprintf( szClientIp, INET_ADDRSTRLEN - 1, "0.0.0.0" );
|
||||
}
|
||||
|
||||
// client 를 처리할 Thread 객체 생성 후 기동 처리.
|
||||
// - 해당 객체에서 thread 종료시 자동 delete 처리하므로.. 본 함수에서는 new 생성만 처리한다.
|
||||
pClientThread = NULL;
|
||||
pClientThread = new CClientThread( &processStatus, clientSocket, szClientIp );
|
||||
if( pClientThread == NULL || pClientThread->Start() == false )
|
||||
{
|
||||
// Thread 기동 실패시..
|
||||
if( pClientThread != NULL )
|
||||
{
|
||||
LOG( LERR, "client[%s] thread object start function fail.", szClientIp );
|
||||
|
||||
delete pClientThread;
|
||||
pClientThread = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Thead 객체 생성 실패시
|
||||
LOG( LERR, "client[%s] thread object create fail.", szClientIp );
|
||||
}
|
||||
|
||||
close( clientSocket );
|
||||
}
|
||||
}
|
||||
|
||||
} // while( 1 )
|
||||
|
||||
|
||||
// Process 종료 처리.
|
||||
_LOG( LINF, "Worker[%d] exit.. Good Bye..", getpid());
|
||||
|
||||
//잠시 대기 후 종료처리.
|
||||
solusleep(500000);
|
||||
|
||||
// fork 를 수행한 함수에서 exit 함수 호출을 통한 종료처리
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// Worker Process 종료 Signal 을 전달받은 경우 이를 처리하기 위한 함수.
|
||||
// @param nSignalNumber [in] 발생한 시그널 Number
|
||||
// @return void
|
||||
static void SignalWorkerTerminate(int nSignalNumber)
|
||||
{
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
_LOG( LINF, "Worker[%d] process exit by user signal [SIGTERM]. Good Bye..", getpid() );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LWAR, "Worker[%d] process exit by abnormal signal[%d], Good Bye..", getpid(), nSignalNumber );
|
||||
}
|
||||
|
||||
solusleep(500000);
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// Worker 프로세스 signal 처리 설정을 위한 함수
|
||||
// @return void
|
||||
void SetSignalWorker( void )
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
memset(&act, 0x00, sizeof(act));
|
||||
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
sigfillset( &act.sa_mask );
|
||||
|
||||
/* 무시할 신호 목록 */
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL); /* desciptor 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP, &act, NULL); /* process를 기동시킨 관리자의 로그아웃시, 또는 config reload 등의 처리 signal*/
|
||||
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => demon 으로 기동되기 땜시 이 신호 못받음 */
|
||||
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Worker Controller 의 child process 종료에 대한 처리기 설정.
|
||||
act.sa_handler = SIG_DFL; // 외부 프로세스 수행이 발생할 수 있는 경우 default 처리
|
||||
//act.sa_handler = SIG_IGN; // 외부 프로세스 수행이 없는 경우.. SIG_IGN 처리
|
||||
sigaction( SIGCHLD, &act, NULL);
|
||||
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SignalWorkerTerminate;
|
||||
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
|
||||
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
rc_syncd Worker Header ( Worker.h )
|
||||
-----------------------------------------
|
||||
begin : 2014/09/02
|
||||
copyright : (C) 2005 Solbox Inc.
|
||||
author : Storage Dev Team
|
||||
email : storage.sd@solbox.com
|
||||
version : 3.4
|
||||
|
||||
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of Solbox Inc.
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __RC_SYNCD_WORKER_H__
|
||||
#define __RC_SYNCD_WORKER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Worker Process 의 main 함수
|
||||
// @param listenSocket command, data 송수신을 위한 TCP Listen socket
|
||||
// @return EXIT_FAILURE 모듈 초기화 실패시
|
||||
// EXIT_SUCCESS 그 외 정상 종료
|
||||
int WorkerMain( int listenSocket );
|
||||
|
||||
// Worker 프로세스 signal 처리 설정을 위한 함수
|
||||
// @return void
|
||||
void SetSignalWorker( void );
|
||||
|
||||
|
||||
/* Signal 처리를 위한 각 Signal Handler 함수는
|
||||
* 다른 Code 에서 Include 처리시 Static 관련 문제로 인해
|
||||
* 본 Header 에서 선언처리 하지 않음. cpp 에만 존재
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __RC_SYNCD_WORKER_H__ */
|
||||
|
||||
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# -lt 3 ]; then
|
||||
echo "$0 [master data] [slave data] [output file]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff $1 $2 | grep -iE "^>|^<" | sed -e 's|^> ||g' | sed -e 's|^< ||g' > $3
|
||||
@@ -0,0 +1,66 @@
|
||||
#****************************************************************************
|
||||
# Makefile for rc_syncd test client
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2014/09/15
|
||||
# copyright : (C) 2005 Solbox Inc.
|
||||
# author : storage dev team
|
||||
# email : storage.sd@solbox.com
|
||||
# version : 3.4
|
||||
#
|
||||
# CopyRight(C) 2005 Solbox Inc. All Rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or with out
|
||||
# modification, are not permitted in outside of Solbox Inc.
|
||||
#*****************************************************************************
|
||||
|
||||
|
||||
# Program info
|
||||
PROG_NAME = test_client
|
||||
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
|
||||
CFLAGS = -Wall -O3 -g -Wimplicit -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-fno-rtti -D_REENTRANT
|
||||
|
||||
LFLAGS =
|
||||
DFLAGS = -D_DEBUG_ -DPROG_NAME=\"$(PROG_NAME)\"
|
||||
|
||||
|
||||
|
||||
# Enviroment
|
||||
DIR_INCLUDE = -I./. -I./.. -I./../../lib
|
||||
DIR_LIB =
|
||||
|
||||
OBJ = ../../lib/Logger.o ../../lib/BaseSocket.o ../RcSyncdClientSocket.o main_client.o
|
||||
|
||||
|
||||
LIBS =
|
||||
|
||||
APP = $(PROG_NAME)
|
||||
############################
|
||||
|
||||
|
||||
all:$(APP)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(PROG_NAME): $(OBJ)
|
||||
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core *.out *.log ./../*.o
|
||||
-rm -f $(APP)
|
||||
sync
|
||||
|
||||
|
||||
install : $(APP)
|
||||
sync
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,140 @@
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "RcSyncdClientSocket.h"
|
||||
|
||||
|
||||
|
||||
#define LOG_PATH "/user/service/logs"
|
||||
|
||||
#define RC_SYNCD_HOST "127.0.0.1" // rc_syncd host
|
||||
#define RC_SYNCD_LISTEN_PORT 14002 // rc_syncd 의 Listen Port
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Test 용 코드 정의
|
||||
CReqMasterData request;
|
||||
|
||||
request.sync_type = SYNC_TYPE::NORMAL;
|
||||
request.start_time = "20140101125900";
|
||||
request.end_time = "20140915000000";
|
||||
//request.one_service = "501";
|
||||
|
||||
|
||||
|
||||
////////////// Test 코드 //////////////
|
||||
|
||||
// Log 처리용 객체 생성 및 초기화.
|
||||
if( CLogger::Init( PROG_NAME, LOG_PATH, LDBG ) == false )
|
||||
{
|
||||
std::cout << "[error] Logger object created failed.." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Start logging
|
||||
_LOG( LINF, "rc_syncd test client Start");
|
||||
|
||||
|
||||
// rc_syncd 와 통신을 처리할 client socket 객체 생성 및 접속
|
||||
CRcSyncdClientSocket client;
|
||||
if( client.ConnectTarget( RC_SYNCD_HOST, RC_SYNCD_LISTEN_PORT ) == false )
|
||||
{
|
||||
// Source ftsd 으로 접속 실패시
|
||||
_LOG( LERR, "rc_syncd connect fail. [%s][%d]", RC_SYNCD_HOST, RC_SYNCD_LISTEN_PORT );
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// rc_syncd 로 sync 요청 전달
|
||||
if( client.SendSyncRequest( request ) == false )
|
||||
{
|
||||
// 전송 실패시
|
||||
_LOG( LERR, "Sync request send fail");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
// 요청에 대한 응답 대기
|
||||
int nTimeout = 5; // 응답 대기 시간 ( sec )
|
||||
int nResult = 0;
|
||||
|
||||
|
||||
bool bResultSuccess; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
|
||||
std::string strMessage; // 수신 메시지 저장 변수.
|
||||
|
||||
|
||||
// 루프를 돌면서 요청에 대한 응답을 대기
|
||||
while(1)
|
||||
{
|
||||
|
||||
// nTimeout 에 지정된 시간동안 응답대기
|
||||
nResult = client.GetSyncResult( nTimeout, bResultSuccess, strMessage);
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
|
||||
// 해당 내역 로깅 및 루프 종료
|
||||
_LOG( LERR, "Response wait fail by socket" );
|
||||
break;
|
||||
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Allive Check 패킷 한번 쏘고 다시 Loop 로
|
||||
|
||||
if( client.SendAliveCheck() == false )
|
||||
{
|
||||
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
|
||||
_LOG( LERR, "Response wait fail by socket2");
|
||||
break;
|
||||
}
|
||||
|
||||
// 정상적인 경우 다시 응답대기.
|
||||
continue;
|
||||
|
||||
}
|
||||
else if( nResult == 1 )
|
||||
{
|
||||
// 요청에 대한 처리결과 정보가 수신된 경우.
|
||||
// 해당 정보 로깅처리.
|
||||
|
||||
if( bResultSuccess == true )
|
||||
{
|
||||
// 요청에 대한 처리가 정상적으로 처리된 경우
|
||||
_LOG( LINF, "Sync result SUCCESS.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 오류 발생시
|
||||
_LOG( LINF, "Sync result ERROR [%s]", strMessage.c_str() );
|
||||
|
||||
}
|
||||
|
||||
break; // 응답을 받았으니 응답 대기 루프 종료
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replication 요청에 대한 응답패킷이 아닌 경우.
|
||||
// 해당 패킷은 무시하고 다시 Loop 로
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
client.Close();
|
||||
|
||||
|
||||
// End logging
|
||||
_LOG( LINF, "test client end");
|
||||
_LOG( LINF, "-------------------------------------------------------------------------------" );
|
||||
|
||||
CLogger::Exit();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
CMD="$1"
|
||||
SLEEP="$2"
|
||||
|
||||
while [ 1 ]; do
|
||||
date
|
||||
eval $CMD
|
||||
echo " "
|
||||
sleep $SLEEP
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user