base
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
Revision 1446
|
||||
-------------------
|
||||
수정일 : 2018-04-11
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 비정상적인 작업에 대한 프로세스 비정상 종료 발생
|
||||
- 작업 목록에 파싱 상태 체크 로지 수행 위치 변경
|
||||
|
||||
- BUG: lock 파일 삭제 인한 중복 파일 발생
|
||||
- lock 획득적 lock 상태 확인 로직 추가
|
||||
|
||||
|
||||
Revision 1444
|
||||
-------------------
|
||||
수정일 : 2018-02-28
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: lock 파일 생성 실패로 인한 중복 파일 발생
|
||||
- 정상적인 작업 완료된 경우만 해당 파일 삭제 처리
|
||||
- lock 관련 파일이 /tmp 쓰레기 처럼 존재할 수 있음(해당 clean 작업은 외부 tool 활용(e.g. cornjob))
|
||||
|
||||
|
||||
Revision 1376
|
||||
-------------------
|
||||
수정일 : 2016-05-23
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 삭제된 컬럼 참조
|
||||
- DB connection pool alive 체크 로직에서 삭제된 컬럼 참조함
|
||||
|
||||
|
||||
Revision 1310
|
||||
-------------------
|
||||
수정일 : 2015-12-21
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: Revision 1309 컴파일 오류 수정
|
||||
|
||||
|
||||
Revision 1309
|
||||
-------------------
|
||||
수정일 : 2015-12-21
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: sleep 루틴 오동작
|
||||
- 몇 초 가량 sleep 되어야하는 로직이 무차별하게 실행되는 버그가 발견됨
|
||||
- nanosleep 함수를 제대로 사용하지 않아서 발생한 문제임
|
||||
|
||||
|
||||
Revision 1241
|
||||
-------------------
|
||||
수정일 : 2015-09-23
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: usleep -> nanosleep 으로 변경 처리
|
||||
- usleep 사용시 multi thread 환경에서 block 발생 가능성이 존재
|
||||
|
||||
|
||||
Revision 1228
|
||||
-------------------
|
||||
수정일 : 2015-09-11
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: BaseSocket 수정 내역 반영
|
||||
|
||||
|
||||
Revision 1209
|
||||
-------------------
|
||||
수정일 : 2015-06-23
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: FHS 이관 되지 않는 파일 지원 스크립트
|
||||
- 이관 파일될 파일을 모든 대상 서버가 가진 경우 처리할 수 있는 스크립트 지원
|
||||
|
||||
|
||||
Revision 1194
|
||||
-------------------
|
||||
수정일 : 2015-03-27
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 동기화 중 비정상 종료
|
||||
- 소스 uri 처리 중 버퍼 Overflow 인하여 비정상 종료 발생함
|
||||
|
||||
|
||||
Revision 1169
|
||||
-------------------
|
||||
수정일 : 2015-01-27
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 디렉토리 동기화되지 않는 버그 발생
|
||||
- Revision 1167 변경된 기능 때문에 발생한 버그임
|
||||
- 디렉토리 동기화(서비스간) 경우 host 관련 필드 없기 때문에 쿼리 생성 시
|
||||
예외 처리되지 않아서 발생한 문제임
|
||||
|
||||
|
||||
Revision 1167
|
||||
-------------------
|
||||
수정일 : 2015-01-27
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: FHS 이관 중 중복 파일 생성 발생
|
||||
- 복제본을 갖은 서비스에 대해서 FHS 이관 중 원복과 복제본이 동일 장비로
|
||||
이관되는 현상 발생함
|
||||
- 원인 : 자기 자신만 제외하고 이관 대상 장비 선정 로직 때문에 발생함
|
||||
- 해결 : 자기 이외 가진 장비 목록도 제외되도록 수정함
|
||||
|
||||
- CHG: 특정 FHS에 특정 서비스만 이관 목록 추출 기능
|
||||
|
||||
|
||||
Revision 1164
|
||||
-------------------
|
||||
수정일 : 2015-01-21
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 중복 파일 생성 발생
|
||||
- lock 파일을 통한 프로세스 간 중복 수행 방지하고 있음
|
||||
- lock 파앨 생성 실패 시 중복 파일 발생함
|
||||
- 해당 파일 생성 실패를 오류 처리하여 중복 파일 생성되지 않게 수정함
|
||||
|
||||
|
||||
Revision 1129
|
||||
-------------------
|
||||
수정일 : 2014-11-17
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: 동기화 tools 통합
|
||||
- svcsync 기능과 rc_cmove 기능 통합
|
||||
|
||||
- CHG: 검증 로직 변경
|
||||
- 기능 통합에 따른 검증 로직 변경
|
||||
|
||||
- CHG: DNS resolve 실패 관련 기능 보강
|
||||
|
||||
- CHG: DB 접속 시 응용프로그램명 추가
|
||||
|
||||
- NEW: rc_syncd와 통신 기능 추가
|
||||
|
||||
|
||||
Revision 1046
|
||||
-------------------
|
||||
수정일 : 2014-08-04
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 복제 속성 가진 파일 이동되지 않는 버그
|
||||
- 검증 로직 쿼리 구문에 ic_cache = 'N' 값을 참조하여 발생한 버그 였음
|
||||
|
||||
|
||||
Revision 1030
|
||||
-------------------
|
||||
수정일 : 2014-07-28
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: 사용되지 않는 컬럼 연관 로직 정리
|
||||
- get_content_language,get_etag,supported_lock,lock_discovery 연관된 로직 삭제 처리
|
||||
|
||||
|
||||
Revision 1001
|
||||
-------------------
|
||||
수정일 : 2014-07-02
|
||||
수정자 : 노경민
|
||||
|
||||
- CHG: 메타 테이블 분리에 따른 로직 수정
|
||||
- 메타 테이블 참조 쿼리 변경함
|
||||
|
||||
Revision 0989
|
||||
-------------------
|
||||
수정일 : 2012-05-10
|
||||
수정자 : 노경민
|
||||
|
||||
- BUG: 동기화되지 않는 경우 발생
|
||||
- 디렉토리 동기화 실패
|
||||
- 원인 : open-dav Revision 0744 이후 디렉토리 대한 filename_hash, filename_org 생성되지
|
||||
않고 있지만 동기화로직에서 해당 값이 없을 시 에러로 처리하여 동기화 되지 않았음
|
||||
- 삭제된 파일로 오인하여 동기화 되지 않는 경우
|
||||
- 원인 : 리소스ID를 가장 큰 값을 최신 소스로 판단하여 해당 값을 검증로직에서
|
||||
사용하여 발생한 문제임
|
||||
|
||||
|
||||
Revision 0777
|
||||
-------------------
|
||||
수정일 : 2012-06-01
|
||||
수정자 : 노경민
|
||||
|
||||
- NEW: SVN 신규 등록
|
||||
- rc_cmove는 동일 RC 내 컨텐츠를 이관 시킬 수 있는 command tool이다.
|
||||
- CHG:
|
||||
- BUG:
|
||||
@@ -0,0 +1,37 @@
|
||||
#****************************************************************************
|
||||
# Makefile for storagesync ( Storage Sync Command Line Tool)
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2012/05/13
|
||||
# copyright : (C) 2012 SolutionBox Inc.
|
||||
# author : Service 1 Team
|
||||
# email : svc1@solbox.com
|
||||
# version : 3.1.0
|
||||
#
|
||||
# CopyRight(C) 2005 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.
|
||||
#*****************************************************************************
|
||||
|
||||
SUBDIRS = lib src
|
||||
|
||||
.PHONY: all $(SUBDIRS)
|
||||
|
||||
|
||||
all: $(SUBDIRS)
|
||||
sync;
|
||||
|
||||
|
||||
$(SUBDIRS):
|
||||
$(MAKE) all -C $@
|
||||
|
||||
|
||||
install:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) install); done
|
||||
|
||||
|
||||
clean:
|
||||
@for dir in $(SUBDIRS); do (cd $$dir; $(MAKE) clean); done
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,595 @@
|
||||
#include "BaseSocket.h"
|
||||
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define MAX_SEND_RETRY_COUNT 10 // Socket send 실패시 최대 재전송 시도 횟수.
|
||||
|
||||
|
||||
/// @brief 생성자.
|
||||
/// @param socket [in] 처리할 socket descriptor
|
||||
CBaseSocket::CBaseSocket( const int& socket )
|
||||
: m_sock( socket )
|
||||
{
|
||||
if( m_sock < 0 )
|
||||
{
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
m_bConnected = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 소멸자
|
||||
CBaseSocket::~CBaseSocket()
|
||||
{
|
||||
// 소멸자 Socket 명시적 Close 처리.
|
||||
Close();
|
||||
}
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void CBaseSocket::Close()
|
||||
{
|
||||
m_bConnected = false;
|
||||
|
||||
if( m_sock != SOCKET_NOT_VALID )
|
||||
{
|
||||
close( m_sock );
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool CBaseSocket::Connect( const std::string& szTarget, int nPort )
|
||||
{
|
||||
// 기존 접속을 Close 처리
|
||||
Close();
|
||||
|
||||
unsigned int nHost = ConversionAddr( szTarget.c_str() );
|
||||
if( nHost == INADDR_NONE )
|
||||
{
|
||||
LOG( LERR, "target host name resolve fail. [%s]->INADDR_NONE", szTarget.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in stTargetAddr;
|
||||
|
||||
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if( m_sock == -1 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
LOG( LERR, "socket create failed.[%d][%s] Target:[%s]", errorNum, strerror(errorNum), szTarget.c_str() );
|
||||
|
||||
m_sock = SOCKET_NOT_VALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
stTargetAddr.sin_family = AF_INET;
|
||||
stTargetAddr.sin_addr.s_addr = nHost;
|
||||
stTargetAddr.sin_port = htons( nPort );
|
||||
|
||||
// NEW 2012-05-18 huibong
|
||||
// Connnection 종료시 많은 TIME_WAIT 상태 발생으로 인해 .. 이를 제거하기 위해 SO_LINGER 옵션을 설정처리한다.
|
||||
struct linger opt_linger;
|
||||
opt_linger.l_onoff = 1; /* LINGER ON */
|
||||
|
||||
// CHG 2014-05-27 huibong
|
||||
// 아래와 같이 No Wait 로 처리할 경우... Server 역활 수행 중 Close 신호를 받지 못하는 경우가 발생 가능함.
|
||||
// 따라서 5 sec 정도 대기하도록 수정 처리한다.
|
||||
//opt_linger.l_linger = 0; /* No Wait => 0 for abortive disconnect */
|
||||
opt_linger.l_linger = 5; // 5 sec 대기
|
||||
|
||||
int result = setsockopt( m_sock, SOL_SOCKET, SO_LINGER, &opt_linger, sizeof(opt_linger));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_LINGER set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
/* Send Timeout 설정. */
|
||||
struct timeval tv_timeo = { 5, 0 };
|
||||
|
||||
result = setsockopt( m_sock, SOL_SOCKET, SO_SNDTIMEO, &tv_timeo, sizeof(tv_timeo));
|
||||
if( result != 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "setsockopt func SO_SNDTIMEO set fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
}
|
||||
|
||||
if(connect(m_sock, (struct sockaddr *)&stTargetAddr, sizeof(stTargetAddr)) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "connect fail.[%s][%d] [%d][%s]", szTarget.c_str(), nPort, errorNum, strerror( errorNum ) );
|
||||
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bConnected = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool CBaseSocket::IsValidSocket()
|
||||
{
|
||||
if( m_sock != SOCKET_NOT_VALID && m_bConnected == true )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::Read( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
while( (nRead = read( m_sock, vptr, size )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2010-07-23 BUG huibong 잘못된 대입연산자를 비교연산자로 수정.
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return nRead;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::ReadN( void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류 , -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t CBaseSocket::ReadNTimeout2( void * vptr, size_t size, int timeout )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
ssize_t nRead = 0;
|
||||
size_t nLeft = size;
|
||||
char * ptr = (char *)vptr;
|
||||
int errorNum;
|
||||
|
||||
// 우선은 읽기 시도.
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nRead = 0;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
|
||||
// 만약 더 받을 데이터가 존재한다면.
|
||||
if( nLeft > 0 )
|
||||
{
|
||||
struct timeval timeOver;
|
||||
int result;
|
||||
|
||||
fd_set selectFds;
|
||||
FD_ZERO( &selectFds );
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
timeOver.tv_sec = timeout;
|
||||
timeOver.tv_usec = 0;
|
||||
FD_SET( m_sock, &selectFds );
|
||||
|
||||
result = select( m_sock+1, &selectFds, (fd_set *)NULL, (fd_set *)NULL, &timeOver );
|
||||
|
||||
if( result > 0 )
|
||||
{
|
||||
if( FD_ISSET( m_sock, &selectFds ))
|
||||
{
|
||||
if( (nRead = read( m_sock, ptr, nLeft) ) < 0 )
|
||||
{
|
||||
errorNum = errno;
|
||||
if(errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK)
|
||||
{
|
||||
nRead = 0;
|
||||
continue;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "read func fail.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nRead == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nLeft -= nRead;
|
||||
ptr += nRead;
|
||||
}
|
||||
}
|
||||
else if( result == 0 ) // Timeout
|
||||
{
|
||||
//LOG( LDBG, "read timeout");
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorNum = errno;
|
||||
LOG( LERR, "select func error.[%d][%s]", errorNum, strerror(errorNum) );
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t CBaseSocket::WriteN( const void * vptr, size_t size )
|
||||
{
|
||||
if( IsValidSocket() == false )
|
||||
return 0;
|
||||
|
||||
size_t nLeft;
|
||||
ssize_t nWrite;
|
||||
|
||||
const char * ptr = (const char *)vptr;
|
||||
nLeft = size;
|
||||
|
||||
int nTryCount = 0;
|
||||
|
||||
while( nLeft > 0 )
|
||||
{
|
||||
if( (nWrite = send( m_sock, ptr, nLeft, 0 )) < 0 )
|
||||
{
|
||||
int errorNum = errno;
|
||||
|
||||
if( errorNum == EINTR || errorNum == EAGAIN || errorNum == EWOULDBLOCK )
|
||||
{
|
||||
nWrite = 0;
|
||||
++nTryCount;
|
||||
}
|
||||
else if( errorNum == ECONNRESET || errorNum == EPIPE )
|
||||
{
|
||||
// 2015-08-28 CHG huibong EPIPE(32) 오류 발생시.. 연결 종료로 처리되도록 수정
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG( LERR, "send func fail.[%d][%s]", errorNum, strerror(errorNum));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if( nWrite == 0 )
|
||||
{
|
||||
m_bConnected = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( nTryCount > MAX_SEND_RETRY_COUNT )
|
||||
{
|
||||
LOG( LERR, "send func failure due to exceeding count of retry[%d/%d]", nTryCount, MAX_SEND_RETRY_COUNT );
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
nLeft -= nWrite;
|
||||
ptr += nWrite;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// CHG 2011-05-03 huibong
|
||||
// gethostbyname() 함수가 Thread Safe 하지 않기 때문에
|
||||
// DNS resolve 처리시 잘못된 정보를 반환할 가능성이 존재
|
||||
// 이에 따라 본 함수를 수정처리함.
|
||||
/*
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
struct hostent *he;
|
||||
int max;
|
||||
unsigned int retval;
|
||||
|
||||
if ((retval = inet_addr(name)) != INADDR_NONE)
|
||||
return retval;
|
||||
|
||||
he = gethostbyname(name);
|
||||
if (he == NULL)
|
||||
return INADDR_NONE;
|
||||
|
||||
for (max = 0; he->h_addr_list[max]; max++) ;
|
||||
if (max == 1)
|
||||
return *((unsigned int *)(he->h_addr_list[0]));
|
||||
else
|
||||
return *((unsigned int *)(he->h_addr_list[random() % max]));
|
||||
}
|
||||
*/
|
||||
|
||||
unsigned int CBaseSocket::ConversionAddr( const char * name )
|
||||
{
|
||||
unsigned int retval;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
int error;
|
||||
|
||||
|
||||
// 전달받은 정보가 IP 주소인 경우...
|
||||
// - DNS resolve 할 필요 없이 변환시킨 값을 그대로 사용한다.
|
||||
if( (retval = inet_addr(name)) != INADDR_NONE )
|
||||
return retval;
|
||||
|
||||
// getaddrinfo() 함수 호출을 위한 Hint 설정
|
||||
memset( &hints, 0x00, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
// Thread Safe 한 DNS Resolve 처리함수 호출
|
||||
// int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
// CHG 2014-11-14 huibong
|
||||
// getaddrinfo 호출시 종종 EAI_NONAME 오류가 반환됨. (#20783)
|
||||
// - 따라서 오류 반환시 재시도하도록 기능 추가
|
||||
// CHG 2015-07-15 huibong
|
||||
// usleep 의 multi thread 상에서 block 발생 가능
|
||||
// - nanosleep 을 사용토록 변경 처리
|
||||
for( int count = 0 ; count < 3; count++ )
|
||||
{
|
||||
error = getaddrinfo( name, NULL, &hints, &result );
|
||||
|
||||
// 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
if( result != NULL)
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
// 잠시 대기 후 재시도 처리
|
||||
struct timespec sleep;
|
||||
sleep.tv_sec = 0;
|
||||
sleep.tv_nsec = 500000000; // 0.5 sec
|
||||
nanosleep( &sleep, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정상 처리된 경우...
|
||||
// - loop 탈출
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 오류 발생시
|
||||
if( error != 0 )
|
||||
{
|
||||
LOG( LERR, "name[%s] dns resolve fail. getaddrinfo return error [%d][%s]", name, error, gai_strerror(error) );
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
|
||||
retval = (unsigned int)(addr->sin_addr.s_addr);
|
||||
|
||||
// DNS Resovle 결과 확인용 코드
|
||||
/*
|
||||
struct addrinfo *temp;
|
||||
for( temp = result; temp; temp = temp->ai_next )
|
||||
{
|
||||
addr = (struct sockaddr_in *)temp->ai_addr;
|
||||
printf ("getaddrinfo result = %s\n",inet_ntoa( addr->sin_addr));
|
||||
}
|
||||
*/
|
||||
|
||||
// getaddrinfo() 함수에서 생성한 메모리 영역 해제 처리.
|
||||
freeaddrinfo(result);
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/***************************************************************************
|
||||
BaseSocket ( Base Socket Class )
|
||||
-----------------------------------------
|
||||
begin : 2010/03/02
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 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_BASE_SOCKET_H__
|
||||
#define __LIBRARY_BASE_SOCKET_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
#define SOCKET_NOT_VALID -1
|
||||
#define DEFAULT_DATA_RECEIVE_TIMEOUT 15 // sec
|
||||
|
||||
|
||||
class CBaseSocket
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief socket descriptor
|
||||
int m_sock;
|
||||
|
||||
/// @brief socket 의 연결상태인지 여부를 저장하기 위한 변수.
|
||||
bool m_bConnected;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// @brief 생성자.
|
||||
CBaseSocket( const int & socket );
|
||||
|
||||
/// @brief 소멸자.
|
||||
~CBaseSocket();
|
||||
|
||||
/// @brief 소켓의 Close 처리를 수행함.
|
||||
void Close(void);
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool Connect( const std::string& szTarget, int nPort );
|
||||
|
||||
/// @brief 멤버 변수인 m_sock 이 유효하고 연결된 상태인 경우 true 반환.
|
||||
/// @return socket이 유효하지 않거나 연결이 끊어지 경우 false 반환, 그외에는 true 반환.
|
||||
bool IsValidSocket(void);
|
||||
|
||||
/// @brief 멤버변수인 socket 의 접속 상태 여부를 설정하기 위한 함수.
|
||||
void SetConnectionStatus( bool bConnected) { m_bConnected = bConnected; }
|
||||
|
||||
/// @brief 현재 socket 의 접속 상태를 반환.
|
||||
bool GetConnectionStatus( void) { return m_bConnected; }
|
||||
|
||||
//void SetLogger( Logger * pLog ) { m_pLog = pLog; }
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief m_sock 로 부터 지정된 size 만큼 데이터 read 를 시도 ( read 함수와 동일 )
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t Read( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t ReadN( void * vptr, size_t size );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
/// @brief m_sock 로부터 지정된 size 만큼 read 를 시도, \n
|
||||
///< 만약 지정된 크기만큼 데이터가 존재하지 않을 경우 해당 크기만큼 데이터를 read 할때까지 대기. \n
|
||||
///< 또는 지정된 Timeout 값 동안 read 를 하지 못하는 경우 오류 처리.
|
||||
///< 본 함수는 Socket 상에 이미 Data 가 존재하는 경우에만 사용.
|
||||
/// @param vptr [out] Read 된 데이터를 저장하기 위한 변수에 대한 포인터.
|
||||
/// @param size [in] read 하고자 하는 데이터의 크기.
|
||||
/// @param timeout [in] Timeout value (sec)
|
||||
/// @return read 된 데이터의 크기. 0: fd closed, -1: 오류, -2: Timeout
|
||||
ssize_t ReadNTimeout2( void * vptr, size_t size, int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT );
|
||||
|
||||
public:
|
||||
/// @brief m_sock 으로 지정된 크기만큼 vptr 의 데이터를 전송 시도.\n
|
||||
///< Send Timeout 옵션 설정으로 Write Timeout 설정 가능. \n
|
||||
///< 지정된 횟수만큼 재전송 실패시 오류로 처리함.
|
||||
/// @param vptr [in] 전달할 데이터를 저장한 변수에 대한 포인터.
|
||||
/// @param size [in] write 하고자 하는 데이터의 크기.
|
||||
/// @return write 된 데이터의 크기. 0: fd closed, -1: 오류
|
||||
ssize_t WriteN( const void * vptr, size_t size );
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief 문자열로 전달받은 정보를 검사하여 IP 접속 정보를 생성한다.
|
||||
unsigned int ConversionAddr( const char * name );
|
||||
|
||||
};
|
||||
|
||||
#endif /* __LIBRARY_BASE_SOCKET_H__ */
|
||||
@@ -0,0 +1,215 @@
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/algorithm/string.hpp> // use boost
|
||||
|
||||
|
||||
Config::Config()
|
||||
: m_keyDelimiter( CONFIG_DEFAULT_KEY_DELIMITER )
|
||||
, m_valueDelimiter( CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// @brief destructor
|
||||
Config::~Config()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Open( const string path )
|
||||
{
|
||||
ifstream file;
|
||||
|
||||
// Config file open
|
||||
file.open( path.c_str());
|
||||
if( file.is_open() == false )
|
||||
{
|
||||
cerr << "[error] " << __FILE__<< ":" << __func__ << ": config file open failed.[" << path << "][" << strerror( errno ) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기존 데이터가 존재하면 삭제 처리.
|
||||
if( m_configData.empty() == false )
|
||||
m_configData.clear();
|
||||
|
||||
// config file parsing
|
||||
string line;
|
||||
string section;
|
||||
vector< string > configs;
|
||||
|
||||
// 루프를 돌면서 Config 파일을 line 단위로 읽어들인당....
|
||||
while( std::getline( file, line ) )
|
||||
{
|
||||
// 앞뒤 공백 제거 처리
|
||||
boost::trim( line );
|
||||
|
||||
// 공백 or 주석처리 라인 검사
|
||||
if( line.empty() == true || boost::starts_with( line, string("#") ) == true || line == "\r" )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Section 여부 검사
|
||||
if( boost::starts_with( line, string("[") ) == true && boost::ends_with( line, string("]") ) == true )
|
||||
{
|
||||
// [] 로 정의된 section 의 문자열 값 추출
|
||||
line.erase( line.begin() );
|
||||
line.erase( line.end() -1 );
|
||||
boost::trim( line );
|
||||
|
||||
if( section.empty() == false && section != line )
|
||||
{
|
||||
// 이전 세션과 다른 신규 세션인 경우
|
||||
// 기존까지 저장했던 데이터를 멤버 변수에 입력 처리 후 내부변수 초기화 처리.
|
||||
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
section.clear();
|
||||
configs.clear();
|
||||
}
|
||||
|
||||
// 신규 section 정보 저장처리.
|
||||
section = line;
|
||||
line.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Section 정보가 아닌 경우 => 실제 설정값 .. ^^
|
||||
configs.push_back( line );
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 세션 처리된 정보가 존재하는 경우 멤버 변수에 저장 처리.
|
||||
if( section.empty() == false )
|
||||
{
|
||||
m_configData.insert( make_pair( section, configs ) );
|
||||
}
|
||||
|
||||
// 종료 처리.
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Config::Clear()
|
||||
{
|
||||
m_configData.clear();
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string& section, const string& key, string& value )
|
||||
{
|
||||
// Section 에 대한 임시 데이터 저장객체 생성
|
||||
vector< string > configs;
|
||||
|
||||
// 해당 Section 이 존재하지 않는 경우
|
||||
if( Find( section, configs ) == false )
|
||||
return false;
|
||||
|
||||
string line;
|
||||
string result;
|
||||
vector< string >::const_iterator it;
|
||||
|
||||
// 해당 Key 이 존재하는지 검사
|
||||
for( it = configs.begin(); it != configs.end(); it++)
|
||||
{
|
||||
line = *it;
|
||||
|
||||
// Line 상의 주석 제거
|
||||
string::size_type pos = line.find( '#' );
|
||||
if( pos != string::npos)
|
||||
{
|
||||
line = line.substr(0, pos);
|
||||
boost::trim( line );
|
||||
}
|
||||
|
||||
// key = value 에서 key 부분 추출
|
||||
pos = line.find( m_keyDelimiter );
|
||||
if( pos == string::npos )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = line.substr(0, pos);
|
||||
boost::trim( result );
|
||||
}
|
||||
|
||||
if( key == result )
|
||||
{
|
||||
// Key 값이 동일한 경우
|
||||
value = line.substr( pos+1 );
|
||||
boost::trim( value );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::GetConfig( const string& section, const string& key, vector< string >& value )
|
||||
{
|
||||
string result;
|
||||
vector< string > vec;
|
||||
|
||||
if( GetConfig( section, key, result ) == false )
|
||||
return false;
|
||||
|
||||
// 전달받은 result 값을 value delimiter 를 이용하여 parsing 처리
|
||||
boost::split( vec, result, boost::is_any_of( m_valueDelimiter ));
|
||||
if( vec.empty() == true )
|
||||
return false;
|
||||
|
||||
// 루프를 돌면서 trim 처리 후 결과값 저장처리.
|
||||
vector< string >::const_iterator it;
|
||||
for( it = vec.begin(); it != vec.end(); it++)
|
||||
{
|
||||
result = boost::trim_copy( *it );
|
||||
|
||||
if( result.empty() == false )
|
||||
value.push_back( result );
|
||||
}
|
||||
|
||||
if( value.empty() == true )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Config::Find( const string& section, vector<string>& configData )
|
||||
{
|
||||
map< string, vector< string > >::iterator it = m_configData.find( section );
|
||||
if( it != m_configData.end() )
|
||||
{
|
||||
// 해당 section 을 찾은 경우
|
||||
configData = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 해당 section 을 찾지 못한 경우
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/***************************************************************************
|
||||
Config File Parser Class
|
||||
-----------------------------------------
|
||||
begin : 2010/02/27
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 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_CONFIG_H__
|
||||
#define __LIBRARY_CONFIG_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#define CONFIG_DEFAULT_KEY_DELIMITER "="
|
||||
#define CONFIG_DEFAULT_VALUE_DELIMITER ","
|
||||
|
||||
|
||||
/// @brief Config class
|
||||
/// 1. config 파일의 내용을 파싱처리하여 각 Section, Key 에 해당하는 값을 반환처리
|
||||
/// 2. config 파일은 [section] 단위로 구분된다.
|
||||
/// 3. config 파일은 key=value 로 구분가능하며 이는 Delimiter 설정을 통해 변경가능하다.
|
||||
/// 4. value 값이 다중으로 존재하는 경우 "," 값을 통해 구분가능, Delimiter 변경시 다른 값도 사용가능함.
|
||||
/// 5. config 파일상에서 "#" 로 시작하는 문자열은 라인 끝까지 주석으로 처리된다.
|
||||
/// 6. 특정 Key 값에 대한 다중 value 값 조회는 vector<string> 을 통해 수행한다.
|
||||
/// 7. 만약 다중 value 값이 존재시 string 으로 반환받을 경우 해당 Row 가 통째로 반환된다.
|
||||
/// 8. 본 객체는 Open , Clear 함수가 호출되기전까지 이전 Config 정보가 저장된다.
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
/// @brief config information saved variable
|
||||
// string : section data
|
||||
// vector<string> : key=value data
|
||||
map< string, vector< string> > m_configData;
|
||||
|
||||
/// @brief Key, Value 구분자 저장 변수
|
||||
string m_keyDelimiter;
|
||||
string m_valueDelimiter;
|
||||
|
||||
public:
|
||||
/// @brief constructor
|
||||
Config();
|
||||
|
||||
/// @brief destructor
|
||||
~Config();
|
||||
|
||||
/// @brief 지정된 Config 파일의 모든 정보를 읽어 내부 변수에 저장처리
|
||||
/// @param path [in] Config file 의 전체 경로정보( C 배열 지원을 위해 & 사용안함)
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Open( const string path );
|
||||
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 삭제처리.
|
||||
/// @return void
|
||||
void Clear();
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 변수
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string& section, const string& key, string& value );
|
||||
|
||||
/// @brief 해당 Section, Key 에 해당하는 value Array 값을 찾아 반환
|
||||
/// @param section [in] 찾고자 하는 Section 값
|
||||
/// @param key [in] 찾고자 하는 key 값
|
||||
/// @param value [out] 해당 Section, Key 에 해당하는 value 값을 저장하기 위한 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool GetConfig( const string& section, const string& key, vector< string >& value );
|
||||
|
||||
/// @brief Key, Value Delimiter Get 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값
|
||||
void GetDelimiter( string& key, string& value )
|
||||
{
|
||||
key = m_keyDelimiter;
|
||||
value = m_valueDelimiter;
|
||||
}
|
||||
|
||||
// BUG 2010-12-06 huibong
|
||||
// string& value = CONFIG_DEFAULT_VALUE_DELIMITER 값은 문법상 오류 구문임.
|
||||
// gcc 3.4.6 버전에서는 Compile 되나 gcc 4.4.5 에서는 error 로 처리되어 수정처리함.
|
||||
|
||||
/// @brief Key, Value Delimiter Set 함수
|
||||
/// @param key [out] key delimiter 값
|
||||
/// @param value [out] value delimiter 값, 지정하지 않을 경우 Default 값이 사용됨.
|
||||
void SetDelimiter( string& key, string value = CONFIG_DEFAULT_VALUE_DELIMITER )
|
||||
{
|
||||
m_keyDelimiter = key;
|
||||
m_valueDelimiter = value;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/// @brief Config 멤버 변수에 저장된 데이터 중 해당 Section 에 해당하는 데이터 반환.
|
||||
/// @param section [in] section 명
|
||||
/// @param configData [out] 해당 Section 에서 읽은 Cofig 정보를 저장할 string 배열
|
||||
/// @return On success return true, otherwise return false
|
||||
bool Find( const string& section, vector<string>& configData );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* __LIBRARY_CONFIG_H__ */
|
||||
@@ -0,0 +1,482 @@
|
||||
/***************************************************************************
|
||||
Logger.cpp
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 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 "Logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
#define DEFAULT_LOG_LEVEL LINF
|
||||
|
||||
using namespace std;
|
||||
|
||||
CLogger* CLogger::m_pInstance = NULL;
|
||||
bool CLogger::m_bIsInitialized = false;
|
||||
pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
CLogger::CLogger( string programName, string logDir, int logLevel )
|
||||
{
|
||||
m_szProgramName = programName;
|
||||
m_szLogDir = logDir;
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == true )
|
||||
{
|
||||
m_nLogLevel = logLevel;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nLogLevel = DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
|
||||
MakeLogLevelString();
|
||||
}
|
||||
|
||||
void CLogger::MakeLogLevelString()
|
||||
{
|
||||
m_vectorLogLevelString.push_back( "EMR" );
|
||||
m_vectorLogLevelString.push_back( "ALT" );
|
||||
m_vectorLogLevelString.push_back( "CRT" );
|
||||
m_vectorLogLevelString.push_back( "ERR" );
|
||||
m_vectorLogLevelString.push_back( "WAR" );
|
||||
m_vectorLogLevelString.push_back( "NOT" );
|
||||
m_vectorLogLevelString.push_back( "INF" );
|
||||
m_vectorLogLevelString.push_back( "DBG" );
|
||||
m_vectorLogLevelString.push_back( "DEV" );
|
||||
m_vectorLogLevelString.push_back( "DEV1" );
|
||||
m_vectorLogLevelString.push_back( "DEV2" );
|
||||
}
|
||||
|
||||
CLogger::~CLogger()
|
||||
{
|
||||
m_vectorLogLevelString.clear();
|
||||
}
|
||||
|
||||
bool CLogger::Init( string programName, string logDir, int logLevel )
|
||||
{
|
||||
if( m_bIsInitialized == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( programName.empty() == true || logDir.empty() == true )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( MakeLogDir( programName, logDir ) == false )
|
||||
{
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
}
|
||||
|
||||
CLogger::m_pInstance = new CLogger( programName, logDir, logLevel );
|
||||
m_bIsInitialized = true;
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsValidLogLevel( int logLevel )
|
||||
{
|
||||
return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true );
|
||||
}
|
||||
|
||||
bool CLogger::SetLogLevel( int logLevel )
|
||||
{
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nLogLevel = logLevel;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::MakeLogDir( string programName, string logDir )
|
||||
{
|
||||
string path = logDir + "/" + programName;
|
||||
|
||||
struct stat dirStat;
|
||||
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( lstat( path.c_str(), &dirStat ) == 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == true )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "exist file with the same name as log path(" << path << ")." << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 디렉토리 가 존재하지 않는 경우 디렉토리 생성 시도
|
||||
string cmd = "mkdir -p " + path;
|
||||
system( cmd.c_str() );
|
||||
|
||||
if( IsDirectory( path ) == false )
|
||||
{
|
||||
cerr << "can't make log directory. path=" << path << "." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::IsDirectory( string path )
|
||||
{
|
||||
struct stat dirStat;
|
||||
|
||||
if( lstat ( path.c_str(), &dirStat ) != 0 )
|
||||
{
|
||||
cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CLogger::Exit()
|
||||
{
|
||||
if( m_bIsInitialized == false )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock( &m_mutex );
|
||||
|
||||
if( CLogger::m_pInstance != NULL )
|
||||
{
|
||||
delete CLogger::m_pInstance;
|
||||
CLogger::m_pInstance = NULL;
|
||||
m_bIsInitialized = false;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &m_mutex );
|
||||
}
|
||||
|
||||
CLogger* CLogger::GetInstance()
|
||||
{
|
||||
return CLogger::m_pInstance;
|
||||
}
|
||||
|
||||
string CLogger::GetLogFilename( struct tm &timeNow )
|
||||
{
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
|
||||
// Make File Name
|
||||
string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr );
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_DATE, NULL, 0, buffer );
|
||||
}
|
||||
|
||||
bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...)
|
||||
{
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char buffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return Write( logLevel, PREFIX_NONE, NULL, 0, buffer );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...)
|
||||
{
|
||||
if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL )
|
||||
{
|
||||
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 );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
char className[255];
|
||||
string funcPrefix = GetClassName( className, filename );
|
||||
funcPrefix += "::" + string( funcname ) + "()";
|
||||
|
||||
return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer );
|
||||
}
|
||||
|
||||
const char* CLogger::GetClassName( char* className, const char* filename )
|
||||
{
|
||||
if( className == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'className' is NULL." << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( filename == NULL )
|
||||
{
|
||||
cout << "[ERROR] The input argument 'filename' is NULL." << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
int filenameSize = strlen( filename );
|
||||
memcpy( className, filename, filenameSize );
|
||||
|
||||
// find end position
|
||||
char endCharacter = '.';
|
||||
int endPos = filenameSize - 1;
|
||||
for( ; endPos > 0; --endPos )
|
||||
{
|
||||
if( className[endPos] == endCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( endPos == 0 )
|
||||
{
|
||||
cout << "[ERROR] endPos=0" << endl;
|
||||
strcpy( className, "NULL" );
|
||||
return className;
|
||||
}
|
||||
|
||||
className[endPos] = '\0';
|
||||
|
||||
// find start position
|
||||
char startCharacter = '/';
|
||||
int startPos = endPos - 1;
|
||||
for( ; startPos > 0; --startPos )
|
||||
{
|
||||
if( className[startPos] == startCharacter )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( startPos != 0 )
|
||||
{
|
||||
startPos += 1;
|
||||
}
|
||||
|
||||
return (className + startPos );
|
||||
}
|
||||
|
||||
bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( log == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
char timeStr[256];
|
||||
snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]"
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// Log Level 문자열 검색
|
||||
string szLevel = m_vectorLogLevelString[ logLevel ];
|
||||
|
||||
switch( logPrefix )
|
||||
{
|
||||
case PREFIX_DATE:
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message.
|
||||
fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log );
|
||||
break;
|
||||
|
||||
case PREFIX_FUNCTION:
|
||||
if( functionName == NULL )
|
||||
{
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
/// 형식 예: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12]
|
||||
fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum );
|
||||
break;
|
||||
|
||||
case PREFIX_NONE:
|
||||
/// 형식 예: sample log message.
|
||||
fprintf( pFile, "%s\n", log );
|
||||
break;
|
||||
}
|
||||
// Write to log file
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size )
|
||||
{
|
||||
/// 유효한 로그 레벨이 아니면 로깅하지 않음.
|
||||
if( IsValidLogLevel( logLevel ) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Level 검사 : 지정된 Level 이상인 경우 로깅하지 않음.
|
||||
if( logLevel > m_nLogLevel )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( data == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( size <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Current Data & Time
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
string filename = GetLogFilename( timeNow );
|
||||
|
||||
// Log file open
|
||||
FILE* pFile = NULL;
|
||||
pFile = fopen( filename.c_str(), "a+" );
|
||||
|
||||
if( pFile == NULL )
|
||||
{
|
||||
cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int i = 0; i < size; ++i )
|
||||
{
|
||||
fprintf( pFile, "%02X", data[i] );
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if( ( (i+1) % 8 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 16 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, " " );
|
||||
}
|
||||
|
||||
if( ( (i+1) % 32 ) == 0 )
|
||||
{
|
||||
fprintf( pFile, "\n" );
|
||||
}
|
||||
}
|
||||
fprintf( pFile, "\n" );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
/***************************************************************************
|
||||
Logger.h
|
||||
-----------------------------------------
|
||||
begin : 2011/10/26
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 1.0
|
||||
|
||||
CopyRight(C) 2005 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 __LOGGER_H__
|
||||
#define __LOGGER_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <pthread.h>
|
||||
|
||||
///@brief 로그 레벨 정의
|
||||
#define LEMR 0 /* system is or will be unusable if situation is not resolved */
|
||||
#define LALT 1 /* immediate action required */
|
||||
#define LCRT 2 /* critical situations */
|
||||
#define LERR 3 /* error conditions */
|
||||
#define LWAR 4 /* recoverable errors */
|
||||
#define LNOT 5 /* unusual situation that merits investigation */
|
||||
#define LINF 6 /* information messages */
|
||||
#define LDBG 7 /* verbose data for debugging */
|
||||
#define LDEV 8 /* verbose data for developer */
|
||||
#define LDEV1 9 /* start or end the function of application level */
|
||||
#define LDEV2 10 /* start or end the function of application level */
|
||||
|
||||
#define MAX_LOG_LEVEL LDEV2
|
||||
|
||||
|
||||
///@brief Log 정보를 파일로 저장하기 위한 Class.
|
||||
///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다.
|
||||
///
|
||||
/// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그
|
||||
/// LOG( level, format, ... ) 매크로 사용.
|
||||
/// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger]
|
||||
///
|
||||
/// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그
|
||||
/// _LOG( level, format, ... ) 매크로 사용
|
||||
/// 예) [17:43:40] [EMR] log level emergency
|
||||
///
|
||||
/// 1.3 Prefix가 없는 로그
|
||||
/// _LOG_( level, format, ... ) 매크로 사용
|
||||
/// 예) log level emergency
|
||||
///
|
||||
/// 1.4 Hex 로그.
|
||||
/// LOG_HEX( level, data, size ) 매크로 사용
|
||||
/// 예) 00010203 04050607 08090A0B 0C0D0E0F
|
||||
///
|
||||
///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다.
|
||||
///
|
||||
///3. 로그 파일은 매 일단위로 저장파일이 변경된다.
|
||||
///
|
||||
///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다.
|
||||
///
|
||||
///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다.
|
||||
///
|
||||
///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다.
|
||||
///
|
||||
///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다.
|
||||
///
|
||||
///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다.
|
||||
///
|
||||
class CLogger
|
||||
{
|
||||
// Attributes
|
||||
private:
|
||||
///@brief 싱글톤 객체 인트턴스.
|
||||
static CLogger* m_pInstance;
|
||||
|
||||
///@brief 싱글톤 객체 초기화 여부.
|
||||
static bool m_bIsInitialized;
|
||||
|
||||
///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스.
|
||||
static pthread_mutex_t m_mutex;
|
||||
|
||||
///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szProgramName;
|
||||
|
||||
///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용.
|
||||
std::string m_szLogDir;
|
||||
|
||||
///@brief 로그 레벨.
|
||||
int m_nLogLevel;
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열 정보를 저장.
|
||||
std::vector<std::string> m_vectorLogLevelString;
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 로그 형식을 지정.
|
||||
typedef enum
|
||||
{
|
||||
PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당
|
||||
PREFIX_DATE, /// 클래스 설명의 1.2에 해당
|
||||
PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당
|
||||
} LOG_PREFIX;
|
||||
|
||||
// Operations
|
||||
private:
|
||||
///@brief 생성자.
|
||||
/// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
CLogger( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 소멸자.
|
||||
/// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는
|
||||
/// 벡터 m_vectorLogLevelString을 clear 시킴.
|
||||
virtual ~CLogger();
|
||||
|
||||
///@brief 로그 레벨에 대응되는 문자열을 만든다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
void MakeLogLevelString();
|
||||
|
||||
///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다.
|
||||
/// 생성할 디렉토리 경로는 'logDir/programName'이 된다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@return 디렉토리가 이미 존재하거나 생성 성공하면 true,
|
||||
/// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환.
|
||||
static bool MakeLogDir( std::string programName, std::string logDir );
|
||||
|
||||
///@brief 해당 경로가 디렉토리 인지 아닌지 판단.
|
||||
///@param path [in] 디렉토리 인지 아닌지 판단할 경로.
|
||||
///@return 해당 경로가 디렉토이면 true,
|
||||
/// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환.
|
||||
static bool IsDirectory( std::string path );
|
||||
|
||||
///@brief 로그 레벨이 올바른지 판별.
|
||||
///@param logLevel [in]
|
||||
///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환.
|
||||
static bool IsValidLogLevel( int logLevel );
|
||||
|
||||
///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다.
|
||||
/// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log
|
||||
///param timeNow [in] 현재 시간 정보.
|
||||
///return 로그 파일 이름.
|
||||
std::string GetLogFilename( struct tm &timeNow );
|
||||
|
||||
///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다.
|
||||
/// 쓰레드 안정성을 보장한다.
|
||||
///@param className [out] 파일 이름에서 추출된 클래스명
|
||||
///@param filename [in] 파일 이름.
|
||||
///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL.
|
||||
const char* GetClassName( char* className, const char* filename );
|
||||
|
||||
///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다.
|
||||
/// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param logPrefix [in] 로그 프리픽스 종류.
|
||||
///@functionName [in] ClassName::FunctionNmae() 형식의 문자열.
|
||||
///@lineNum [in] 라인 번호.
|
||||
///@log [in] 출력하고자 하는 로그 내용.
|
||||
bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log );
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다.
|
||||
///@param programName [in] 프로그램 이름
|
||||
///@param logDir [in] 공통 로그 디렉토리 경로
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true,
|
||||
/// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환.
|
||||
static bool Init( std::string programName, std::string logDir, int logLevel );
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 delete 한다.
|
||||
///@param none.
|
||||
///@return none.
|
||||
static void Exit();
|
||||
|
||||
///@brief 싱글톤 객체 m_pInstance를 반환한다.
|
||||
///@param none.
|
||||
///@return CLogger 객체의 인스턴스.
|
||||
static CLogger* GetInstance();
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool Write( int logLevel, const char * fmt, ...);
|
||||
|
||||
///@brief Prefix가 없는 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteNoPrefix( int logLevel, const char * fmt, ...);
|
||||
|
||||
///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param filename [in] 파일 이름
|
||||
///@param funcname [in] 함수 이름
|
||||
///@param lineNum [in] 라인 번호
|
||||
///@param fmt [in] 로그 내용 포맷.
|
||||
///@param __VAR_ARGS__ [in] 가변 인자.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool Write( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...);
|
||||
|
||||
///@brief 로그를 hex 형식으로 저장.
|
||||
///@param logLevel [in] 로그 레벨
|
||||
///@param data [in] hex 형식으로 출력할 데이터.
|
||||
///@pram size [in] data의 크기.
|
||||
///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환
|
||||
bool WriteHex( int logLevel, const unsigned char* data, const int size );
|
||||
|
||||
///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고
|
||||
/// 적절한 값이 아니면 로그 레벨을 변경하지 않는다.
|
||||
///@param logLevel [in] 설정할 로그 레벨
|
||||
///@return none.
|
||||
bool SetLogLevel( int logLevel );
|
||||
|
||||
inline int GetLogLevel() { return m_nLogLevel; };
|
||||
inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; };
|
||||
};
|
||||
|
||||
#define LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->Write( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_( level, format, ... ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
#define _LOG_HEX_( level, data, size ) \
|
||||
if( CLogger::GetInstance() != NULL ) \
|
||||
{ \
|
||||
CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define FUNC_BEGIN() LOG( LDEV1, "begin" )
|
||||
#define FUNC_END() LOG( LDEV1, "end" )
|
||||
|
||||
#define FRM_BEGIN() LOG( LDEV2, "begin" )
|
||||
#define FRM_END() LOG( LDEV2, "end" )
|
||||
|
||||
#endif // __LOGGER_H__
|
||||
@@ -0,0 +1,62 @@
|
||||
#****************************************************************************
|
||||
# Makefile for INTERACTIVE Common Libaray
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2010/02/27
|
||||
# copyright : (C) 2005 SolutionBox Inc.
|
||||
# author : Service 1 Team
|
||||
# email : svc1@solbox.com
|
||||
# version : 1.0
|
||||
#
|
||||
# CopyRight(C) 2005 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.
|
||||
#*****************************************************************************
|
||||
|
||||
# Library info
|
||||
|
||||
LIB_NAME = InterCommon
|
||||
|
||||
LIB = lib$(LIB_NAME).a
|
||||
|
||||
OBJS = Config.o Logger.o BaseSocket.o ReportLog.o
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
AR = /usr/bin/ar
|
||||
|
||||
DIR_INCLUDE = -I/usr/local/include
|
||||
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-D_REENTRANT -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS
|
||||
LFLAGS =
|
||||
DFLAGS =
|
||||
|
||||
############################
|
||||
|
||||
all:$(LIB)
|
||||
sync
|
||||
|
||||
%.o: %.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
|
||||
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) crsv $@ $^
|
||||
|
||||
|
||||
clean:
|
||||
-rm -f *.o core *.out *.log
|
||||
-rm -f $(LIB)
|
||||
sync
|
||||
|
||||
|
||||
install :
|
||||
sync
|
||||
|
||||
|
||||
# End of Makefile
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "ReportLog.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define REPORT_LOG_NAME "report" // Report Log 폴더 및 파일 명칭 지정자..
|
||||
#define MAX_BUFFER_SIZE 2048 // 임시 버퍼 최대 크기
|
||||
|
||||
|
||||
// 생성자..
|
||||
CReportLog::CReportLog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 소멸자..
|
||||
CReportLog::~CReportLog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CReportLog::Init( const char * szPath )
|
||||
{
|
||||
// 멤버 변수 초기화.
|
||||
m_strFullPath.clear();
|
||||
m_strLastError.clear();
|
||||
|
||||
// 변수 유효성 검사.
|
||||
if( szPath == NULL || strlen( szPath ) == 0 )
|
||||
{
|
||||
m_strLastError = "Log path empty.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Log Path check...
|
||||
struct stat dirStat;
|
||||
if( lstat ( szPath, &dirStat ) != 0)
|
||||
{
|
||||
//m_strLastError = "Log path not valid. Check path [" + szPath + "][" + strerror(errno) + "]" ;
|
||||
m_strLastError = "Log path not valid. Check path [";
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append( "][" );
|
||||
m_strLastError.append( strerror(errno) );
|
||||
m_strLastError.append( "]" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// 해당 정보가 Directory 가 아닌 경우
|
||||
if( S_ISDIR( dirStat.st_mode ) == 0 )
|
||||
{
|
||||
if( S_ISLNK( dirStat.st_mode ) == 0 )
|
||||
{
|
||||
//m_strLastError = "Log path not directory or link. Check path [" + szPath + "]";
|
||||
m_strLastError = "Log path not directory or link. Check path [" ;
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append ( "]" );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//m_strLastError = "Log path is symbolic link. path [" + szPath + "]";
|
||||
m_strLastError = "Log path is symbolic link. path [";
|
||||
m_strLastError.append( szPath );
|
||||
m_strLastError.append( "]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 멤버 변수 정보 설정.
|
||||
m_strFullPath = szPath;
|
||||
m_strFullPath.append( "/" );
|
||||
m_strFullPath.append( REPORT_LOG_NAME );
|
||||
|
||||
// 디렉토리 정보 검사
|
||||
if( lstat ( m_strFullPath.c_str(), &dirStat ) == 0)
|
||||
{
|
||||
// 해당 이름을 가진 파일 또는 디렉토리가 존재하고
|
||||
if( S_ISDIR( dirStat.st_mode ) != 0 )
|
||||
{
|
||||
// 해당 이름이 디렉토리인 경우
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종 경로에 대한 Directory 가 존재하지 않는 경우 Directory 생성 시도
|
||||
// 2013-11-27 report 로그는 fluentd 에 의해 감시, 분석되어야 하는데.. root 계정이 아닌 다른 td-agent 계정을 사용함.
|
||||
// 이로 인해 fluentd 에서 report 폴더에 접근할 수 있도록 폴더 권한 설정을 777 로 해야 함.
|
||||
if( mkdir( m_strFullPath.c_str(), 0777 ) != 0 )
|
||||
{
|
||||
m_strLastError = "Log directory create failed. Check path [" + m_strFullPath + "][" + strerror(errno) + "]";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CReportLog::Write( const char * szLevel, const char * fmt, ...)
|
||||
{
|
||||
// Get Current Data & Time
|
||||
char szTimeString[256];
|
||||
time_t now = time( NULL );
|
||||
struct tm timeNow;
|
||||
localtime_r( &now, &timeNow );
|
||||
|
||||
// Make File Name
|
||||
std::string fileName = m_strFullPath + "/" + REPORT_LOG_NAME + "_";
|
||||
snprintf( szTimeString, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday);
|
||||
fileName.append( szTimeString );
|
||||
|
||||
|
||||
// Log file open
|
||||
FILE * pFile = NULL;
|
||||
pFile = fopen( fileName.c_str(), "a+" );
|
||||
if( pFile == NULL )
|
||||
{
|
||||
m_strLastError = "Log file open fail.[" + fileName + "][" + strerror(errno) + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 시간 정보처리
|
||||
snprintf( szTimeString, (size_t)256, "[%04d-%02d-%02d %02d:%02d:%02d]"
|
||||
, timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday
|
||||
, timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec );
|
||||
|
||||
// 가변 인자 처리
|
||||
va_list args;
|
||||
char szBuffer[MAX_BUFFER_SIZE];
|
||||
va_start( args, fmt );
|
||||
if( vsnprintf( szBuffer, MAX_BUFFER_SIZE, fmt, args) < 0 )
|
||||
{
|
||||
va_end( args );
|
||||
fclose( pFile );
|
||||
return false;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
// Write to log file
|
||||
fprintf( pFile, "%s [%s] %s\n", szTimeString, szLevel, szBuffer );
|
||||
fflush( pFile );
|
||||
|
||||
// 종료 처리.
|
||||
fclose( pFile );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
Report 로그 처리용 Class
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/11/25
|
||||
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 __REPORT_LOG_H__
|
||||
#define __REPORT_LOG_H__
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
|
||||
/// @brief CReportLog
|
||||
/// 본 클래스는 전달받은 경로 하위 report 폴더 상에...
|
||||
/// 운영자들에게 전달할 report 관련 log 를 기록하기 위한 클래스임.
|
||||
/// lib 에 존재하는 CLogger Class 가 프로세스에 대해 singleton 방식으로 동작하므로... 해당 Class 를 사용하기는 어려움.
|
||||
/// 따라서 report 관련 로그만 전담하여 처리하기 위한 로그 Class 를 추가함.
|
||||
class CReportLog
|
||||
{
|
||||
public:
|
||||
|
||||
// constructor
|
||||
CReportLog();
|
||||
|
||||
// destructor
|
||||
~CReportLog();
|
||||
|
||||
// 초기화..
|
||||
bool Init( const char * szPath );
|
||||
|
||||
// log wirte
|
||||
bool Write( const char * szLevel, const char * fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
// Get last error log
|
||||
void GetLastError( std::string & errorMessage ) { errorMessage = m_strLastError; return; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// Log Full Path
|
||||
std::string m_strFullPath;
|
||||
|
||||
// last Error String
|
||||
std::string m_strLastError;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* __REPORT_LOG_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(const char *pszQuery)
|
||||
{
|
||||
return this->PgDoExec(pszQuery, NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(string &strQuery)
|
||||
{
|
||||
return this->PgDoExec(strQuery.c_str(), NOT_CLEAR);
|
||||
}
|
||||
|
||||
int DataBase::PgDoExec(const 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(const char *pszQuery);
|
||||
int PgDoExec(const 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,64 @@
|
||||
/***************************************************************************
|
||||
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdProtocol.h )
|
||||
-----------------------------------------
|
||||
begin : 2010/03/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.2.0.R0811
|
||||
|
||||
CopyRight(C) 2005 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 __FTSD_PROTOCOL_H__
|
||||
#define __FTSD_PROTOCOL_H__
|
||||
|
||||
|
||||
struct FileTransferPacketHeader {
|
||||
|
||||
char stx; // Packet 유효성 관리 코드
|
||||
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
|
||||
char command[4]; // Command Code ( 4 Byte) : 0th control-ftsd, 1th ftsd-ftsd 사용.
|
||||
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 0x02
|
||||
|
||||
// Packet Header type 구분코드
|
||||
#define HEADER_TYPE_REQUEST 0x00
|
||||
#define HEADER_TYPE_RESPONSE 0x01
|
||||
|
||||
|
||||
// Packet command 공통.
|
||||
#define COMMON_ALIVE_CHECK 0x7F
|
||||
|
||||
// Packet command : control 프로세스 <-> ftsd 통신 ( Command 첫번째 Byte 만 사용 )
|
||||
#define NOT_CONTROL_COMMAND 0x00 // Control 이 전송한 요청이 아닌 경우.
|
||||
#define CONTROL_FILE_REPLICATION 0x01 // Content 복제 생성 요청
|
||||
#define CONTROL_FILE_CACHE 0x02 // Content 에 대해 Cache 폴더로 복제 요청
|
||||
|
||||
#define CONTROL_FILE_CHECK 0x03 // Content 에 대한 존재 여부, Size 확인 및 Hash 추출 요청
|
||||
#define CONTROL_FILE_UNLINK 0x04 // Content 에 대한 unlink 처리 요청
|
||||
|
||||
|
||||
// Packet Result : type이 Reponse 인 경우에만 세팅됨.( 첫번째 Byte 만 사용시 )
|
||||
#define HEADER_RESULT_SUCCESS 0x00
|
||||
#define HEADER_RESULT_ERROR 0x01
|
||||
|
||||
|
||||
// 기타 정보
|
||||
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
|
||||
|
||||
|
||||
// unlink 요청시 Mode 설정 정보
|
||||
#define UNLINK_MODE_NORMAL 0 // 해당 Content 가 존재하고 size 값이 정확한 경우에만 삭제, 나머지는 오류
|
||||
#define UNLINK_MODE_FORCE 1 // 해당 Content 가 존재하지 않거나.. Size 값이 틀려도 강제로 삭제 처리.. 오류로 처리되는 상황은 통신, 시스템 오류 발생시.
|
||||
|
||||
|
||||
#endif /* __FTSD_PROTOCOL_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,263 @@
|
||||
/***************************************************************************
|
||||
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdSocketControl.h )
|
||||
-----------------------------------------
|
||||
begin : 2010/03/09
|
||||
copyright : (C) 2005 SolutionBox Inc.
|
||||
author : Service 1 Team
|
||||
email : svc1@solbox.com
|
||||
version : 3.2.0.R0811
|
||||
|
||||
CopyRight(C) 2005 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 __FTSD_SOCKET_CONTROL_H__
|
||||
#define __FTSD_SOCKET_CONTROL_H__
|
||||
|
||||
#include "BaseSocket.h"
|
||||
#include "FtsdProtocol.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
///< BYTE 타입 정의
|
||||
#ifndef _BYTE_DEFINED
|
||||
#define _BYTE_DEFINED
|
||||
typedef unsigned char BYTE;
|
||||
#endif // _BYTE_DEFINED
|
||||
|
||||
|
||||
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // SocketControl 에서 사용할 임시버퍼 크기.
|
||||
|
||||
class CFtsdSocketControl : public CBaseSocket
|
||||
{
|
||||
private:
|
||||
|
||||
/// @brief Packet Header 변수
|
||||
struct FileTransferPacketHeader m_packetHeader;
|
||||
|
||||
/// @brief m_packetHeader 구조체의 크기를 저장하기 위한 상수
|
||||
const int m_nPacketHeaderLen;
|
||||
|
||||
/// @brief Packet Header 에 저장된 Data 부분의 길이 정보값.
|
||||
unsigned int m_nPacketDataLen;
|
||||
|
||||
/// @brief Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
|
||||
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// @brief 생성자.
|
||||
CFtsdSocketControl();
|
||||
|
||||
/// @brief 소멸자.
|
||||
~CFtsdSocketControl();
|
||||
|
||||
|
||||
/// @brief 전달받은 Target 으로 Socket 접속을 수행
|
||||
/// @param szTarget [in] 접속 대상 Host name 또는 IP
|
||||
/// @param nPort [in] 접속 Port
|
||||
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
|
||||
bool ConnectTarget( const std::string& szTarget, int nPort );
|
||||
|
||||
|
||||
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Replication 명령 전송.
|
||||
/// @param szFileName [in] 복제할 원본 Source 파일명 (/stg/node0/186/abcde..)
|
||||
/// @param nFileSize [in] 복제할 원본 Source 파일의 크기.
|
||||
/// @param szTargetTranId [in] RC 간 복제 처리시 변경할 대상 Tran ID 정보 값.
|
||||
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
|
||||
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
|
||||
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
|
||||
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
|
||||
///< RC-RC 간 처리시에는 사용하지 않도록 false 로 지정할 것.
|
||||
/// @param vecTargetFhs [in] 복제 대상 Target FHS Host Name 정보
|
||||
/// @return Replication 복제 요청 메시지 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
|
||||
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, const std::string& szTargetTranId, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
|
||||
|
||||
|
||||
/// @brief File Replication 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
|
||||
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
|
||||
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
/// @param bSuccess [out] File Replication 이 정상적으로 수행되었는지 여부 \n
|
||||
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
|
||||
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
|
||||
///< 정상적으로 처리된 경우 true 가 저장되며 \n
|
||||
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
|
||||
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
|
||||
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
|
||||
///< Replication 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
|
||||
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
|
||||
///< Replication 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
|
||||
///
|
||||
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
|
||||
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
|
||||
///<
|
||||
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
|
||||
///< Replication 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
|
||||
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
|
||||
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
|
||||
///< 응답을 대기할 수 있다. \n
|
||||
///<
|
||||
///< 1 : 파일 복제 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
|
||||
///<
|
||||
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Replication 요청에 대한 응답이 아닌 경우 \n
|
||||
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
|
||||
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int GetFileReplicationResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
|
||||
|
||||
|
||||
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Cache 명령 전송.
|
||||
/// @param szFileName [in] Cache 처리할 원본 Source 파일명 (/stg/node0/186/abcde..)
|
||||
/// @param nFileSize [in] Cache 처리할 원본 Source 파일의 크기.
|
||||
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
|
||||
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
|
||||
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
|
||||
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
|
||||
/// @param vecTargetFhs [in] Cache 대상 Target FHS Host Name 정보
|
||||
/// @return Cache 요청 메시지 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendFileCacheRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
|
||||
|
||||
|
||||
/// @brief File Cache 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
|
||||
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
|
||||
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
/// @param bSuccess [out] File Cache 처리가 정상적으로 수행되었는지 여부 \n
|
||||
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
|
||||
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
|
||||
///< 정상적으로 처리된 경우 true 가 저장되며 \n
|
||||
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
|
||||
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
|
||||
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
|
||||
///< Cache 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
|
||||
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
|
||||
///< Cache 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
|
||||
///
|
||||
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
|
||||
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
|
||||
///<
|
||||
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
|
||||
///< Cache 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
|
||||
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
|
||||
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
|
||||
///< 응답을 대기할 수 있다. \n
|
||||
///<
|
||||
///< 1 : 파일 Cache 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
|
||||
///<
|
||||
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Cache 요청에 대한 응답이 아닌 경우 \n
|
||||
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
|
||||
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int GetFileCacheResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
|
||||
|
||||
|
||||
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송.
|
||||
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
|
||||
/// @param bHashCheck [in] Hash 값을 추출할지 여부
|
||||
/// @param nHashCheckSize [in] Hash 값을 추출할 경우 Size 설정값 ( MByte 단위 )\n
|
||||
///< 0 : Content 에 대한 전체 Hash 값을 추출함.
|
||||
///< 숫자 : Content 의 앞 부분부터 지정된 크기 (MByte ) 까지 Hash 값을 추출
|
||||
/// @return Check 요청 메시지 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendFileCheckRequest(const std::string& szFileName, bool bHashCheck, unsigned long long nHashCheckSize );
|
||||
|
||||
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
|
||||
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
|
||||
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
/// @param bSuccess [out] File Check 처리가 정상적으로 수행되었는지 여부 \n
|
||||
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
|
||||
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
|
||||
///< 정상적으로 처리된 경우 true 가 저장되며 \n
|
||||
///< nFileSize, szHashValue 상에 결과 정보가 저장됨.
|
||||
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
|
||||
/// @param nFileSize [out] bSuccess == true 인 경우 요청한 Content 에 대한 file size 정보를 저장. ( Byte 단위 )
|
||||
/// @param szHashValue [out] bSuccess == true 이고... Hash 값 추출을 요청한 경우 추출된 Hash 값 정보를 저장.
|
||||
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
|
||||
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
|
||||
///<
|
||||
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
|
||||
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
|
||||
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
|
||||
///< 응답을 대기할 수 있다. \n
|
||||
///<
|
||||
///< 1 : 파일 Check 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
|
||||
///<
|
||||
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Check 요청에 대한 응답이 아닌 경우 \n
|
||||
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
|
||||
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int GetFileCheckResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, unsigned long long& nFileSize, std::string& szHashValue );
|
||||
|
||||
|
||||
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Unlink 명령 전송.
|
||||
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
|
||||
/// @param nFileSize [in] 원본 파일의 크기 ( Byte 단위 )
|
||||
/// @param bForceUnlink [in] 강제 삭제 처리 여부 ( Defalult false )
|
||||
/// false : 일반모드 - 해당 파일이 존재하고 Size 값이 동일할 경우에만 삭제처리.. 나머지는 오류로 처리.
|
||||
/// true : 강제모드 - 해당 파일이 존재하지 않거나.. Size 가 틀려도 강제로 삭제 처리.. 오류는 통신, 시스템 오류 발생시에만
|
||||
/// @return Unlink 요청 메시지 전송 성공시 true, 실패시 false 반환.
|
||||
bool SendFileUnlinkRequest(const std::string& szFileName, unsigned long long nFileSize, bool bForceUnlink = false );
|
||||
|
||||
/// @brief File Unlink 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
|
||||
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
|
||||
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
|
||||
/// @param bSuccess [out] File unlink 처리가 정상적으로 수행되었는지 여부 \n
|
||||
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
|
||||
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
|
||||
///< 정상적으로 처리된 경우 true 가 저장되며 따로 수신하는 Data 는 없음. \n
|
||||
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
|
||||
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
|
||||
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
|
||||
///<
|
||||
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
|
||||
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
|
||||
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
|
||||
///< 응답을 대기할 수 있다. \n
|
||||
///<
|
||||
///< 1 : 파일 Unlink 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
|
||||
///<
|
||||
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Unlink 요청에 대한 응답이 아닌 경우 \n
|
||||
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
|
||||
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
|
||||
int GetFileUnlinkResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage );
|
||||
|
||||
|
||||
/// @brief 연결된 Socket 통신을 이용하여 내부적으로 정의된 Alive Check 패킷 전송 \n
|
||||
///< => 해당 패킷에 대한 처리는 내부적으로 처리되어 결과값을 확인할 필요는 없다.
|
||||
/// @return Socket 연결 해제 또는 전송 관련 오류 발생시 false, 전송 성공시에는 true 반환.
|
||||
bool SendAliveCheck(void);
|
||||
|
||||
/// @brief Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
|
||||
void PrintHeaderToLog(void);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
|
||||
/// @param timeout [in] 대기시간.
|
||||
/// @retrun 성공시 true, 오류 발생및 실패시 fasle 반환.
|
||||
bool GetPacketHeader(int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);
|
||||
|
||||
/// @brief 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 );
|
||||
|
||||
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
|
||||
/// @param size [in] read 할 데이터 크기
|
||||
/// @return On success return true, otherwise return false.
|
||||
bool GetPacketData( unsigned int size );
|
||||
|
||||
/// @brief pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
|
||||
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
|
||||
|
||||
/// @brief pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
|
||||
unsigned long long GetDataToUInt64( BYTE * pValue );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* __FTSD_SOCKET_CONTROL_H__ */
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#****************************************************************************
|
||||
# Makefile for RC Contents Move Tool
|
||||
# -----------------------------------------
|
||||
#
|
||||
# begin : 2012/05/13
|
||||
# copyright : (C) 2011 SolutionBox Inc.
|
||||
# author : Service 1 Team
|
||||
# email : svc1@solbox.com
|
||||
# version : 3.1.0
|
||||
#
|
||||
# CopyRight(C) 2005 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.
|
||||
#*****************************************************************************
|
||||
|
||||
# Program info
|
||||
PROG_NAME = rc_cmove
|
||||
REVISION = 1446
|
||||
BUILD_DATE = `date +%Y%m%d%H%M%S`
|
||||
PROG_VERSION = 3.5.0.$(REVISION)-$(BUILD_DATE)
|
||||
|
||||
DEFAULT_CONFIG_FILE = /user/service/etc/rcts.conf
|
||||
|
||||
INSTALL_BIN = /user/service/bin
|
||||
|
||||
|
||||
# Compiler info
|
||||
CC = /usr/bin/g++
|
||||
|
||||
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor -Wno-deprecated
|
||||
|
||||
LFLAGS = -lpthread -lcrypt
|
||||
|
||||
# DEBUG or RELEASE Mode select
|
||||
ifeq ($(DEBUG), yes)
|
||||
PROG_VERSION = 3.1.0.$(REVISION)D-$(BUILD_DATE)
|
||||
|
||||
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
|
||||
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
|
||||
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor
|
||||
|
||||
DFLAGS = -D_DEBUG -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D_USE_POSIX_LOCK
|
||||
else
|
||||
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D_USE_POSIX_LOCK
|
||||
endif
|
||||
|
||||
|
||||
# Application Enviroment
|
||||
APP = $(PROG_NAME)
|
||||
|
||||
DIR_LIB = -L../lib
|
||||
|
||||
DIR_INCLUDE = -I./. -I../lib -I/user/db/pgsql/include
|
||||
LIBS = ../lib/libInterCommon.a /user/db/pgsql/lib/libpq.a
|
||||
|
||||
OBJ = Database.o comonusefn.o dbconnpool.o parameter.o \
|
||||
RcSyncdClientSocket.o RcSyncdRequest.o \
|
||||
FtsdSocketControl.o synchronization.o validation.o \
|
||||
workpool.o jobmanager.o monitoring.o main.o
|
||||
|
||||
############################
|
||||
|
||||
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,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,123 @@
|
||||
#include "RcSyncdRequest.h"
|
||||
#include "Logger.h"
|
||||
#include "RcSyncdClientSocket.h" // rc_syncd 와 통신을 처리할 client socket 객체 생성 및 접속
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define RC_SYNCD_HOST "127.0.0.1" // rc_syncd host
|
||||
#define RC_SYNCD_PORT 14002 // OP_PORT = 14002
|
||||
|
||||
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, RC_SYNCD_PORT) == false)
|
||||
{
|
||||
// local rc_syncd 으로 접속 실패시
|
||||
_LOG(LERR, "sync connect fail. [%s][%d]", RC_SYNCD_HOST, RC_SYNCD_PORT);
|
||||
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
|
||||
<< "Sync Server connect fail. [" << RC_SYNCD_HOST << "][" << RC_SYNCD_PORT << "]" << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// rc_syncd로 sync 요청 전달
|
||||
if( client.SendSyncRequest( request ) == false )
|
||||
{
|
||||
// 전송 실패시
|
||||
_LOG( LERR, "Sync request send fail");
|
||||
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
|
||||
<< "Sync request send fail" << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 루프를 돌면서 요청에 대한 응답을 대기
|
||||
while(1)
|
||||
{
|
||||
// nTimeout 에 지정된 시간동안 응답대기
|
||||
nResult = client.GetSyncResult( nTimeout, bResultSuccess, strMessage);
|
||||
|
||||
if( nResult == -1 )
|
||||
{
|
||||
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
|
||||
// 해당 내역 로깅 및 루프 종료
|
||||
_LOG( LERR, "Response wait fail by socket" );
|
||||
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
|
||||
<< "Response wait fail by socket" << std::endl;
|
||||
break;
|
||||
|
||||
}
|
||||
else if( nResult == 0 )
|
||||
{
|
||||
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Alive Check 패킷 한번 쏘고 다시 Loop 로
|
||||
|
||||
if( client.SendAliveCheck() == false )
|
||||
{
|
||||
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
|
||||
_LOG( LERR, "Response wait fail by socket2");
|
||||
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
|
||||
<< "Response wait fail by socket2" << std::endl;
|
||||
break;
|
||||
}
|
||||
LOG( LDBG, "Response wait");
|
||||
// 정상적인 경우 다시 응답대기.
|
||||
continue;
|
||||
}
|
||||
else if( nResult == 1 )
|
||||
{
|
||||
// 요청에 대한 처리결과 정보가 수신된 경우.
|
||||
// 해당 정보 로깅처리.
|
||||
|
||||
if( bResultSuccess == true )
|
||||
{
|
||||
// 요청에 대한 처리가 정상적으로 처리된 경우
|
||||
_LOG( LINF, "Sync result SUCCESS [%s]", strMessage.c_str() );
|
||||
std::cout << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LINF\"] "
|
||||
<< "Sync result SUCCESS [" << strMessage << "]" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 오류 발생시
|
||||
_LOG( LERR, "Sync result ERROR [%s]", strMessage.c_str() );
|
||||
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
|
||||
<<"Sync result ERROR[[" << strMessage << "]" << std::endl;
|
||||
}
|
||||
|
||||
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,190 @@
|
||||
#include "rc_cmove.h"
|
||||
#include "Logger.h"
|
||||
|
||||
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty /*= false*/)
|
||||
{
|
||||
const string strEmpty("");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#define USEC_PER_SEC (1000000LL)
|
||||
long long longtime_now()
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
if( gettimeofday(&tv, NULL) == 0 )
|
||||
{
|
||||
// 성공시 micro-second 단위의 값을 반환
|
||||
return tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 실패시 -1 값을 반환.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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 string(buffer);
|
||||
}
|
||||
|
||||
time_t str2time_t(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);
|
||||
}
|
||||
|
||||
long long str2longtime(string strtime)
|
||||
{
|
||||
return str2time_t(strtime) * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
long GetFileSize(const char* path)
|
||||
{
|
||||
long size = -1;
|
||||
int flag = -1;
|
||||
struct stat buf;
|
||||
|
||||
flag = stat(path, &buf);
|
||||
if(flag == -1)
|
||||
{
|
||||
cerr << "file not found : " << path << endl;
|
||||
return -1;
|
||||
}
|
||||
size = buf.st_size;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if(size == 0)
|
||||
cout << "file size zero : " << path << endl;
|
||||
#endif // _DEBUG
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
string getCommand(string cmd)
|
||||
{
|
||||
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 "";
|
||||
}
|
||||
|
||||
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 "";
|
||||
}
|
||||
|
||||
pclose(stream);
|
||||
return data;
|
||||
}
|
||||
|
||||
string StringReplace(const string& source, const string search, const string replacement)
|
||||
{
|
||||
string r = source;
|
||||
|
||||
string::size_type pos = 0;
|
||||
|
||||
while ( (pos = r.find(search, pos)) != string::npos )
|
||||
{
|
||||
r.replace( pos, search.size(), replacement );
|
||||
pos = pos + replacement.size();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
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,527 @@
|
||||
/***************************************************************************
|
||||
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 "rc_cmove.h"
|
||||
#include "dbconnpool.h"
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define GET_SLEEP 1000 // microsecond
|
||||
|
||||
masterdbpool *masterdbpool::m_inst = NULL;
|
||||
slavedbpool *slavedbpool::m_inst = NULL;
|
||||
|
||||
conndbpool::conndbpool(databaseinfo 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);
|
||||
}
|
||||
|
||||
conndbpool::~conndbpool()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_mutex_destroy(&m_alivemutex);
|
||||
pthread_cond_destroy(&m_alivecond);
|
||||
}
|
||||
|
||||
int conndbpool::CreatePool( int poolcnt /* = 4 */ )
|
||||
{
|
||||
// keep alive thread
|
||||
int nRet = pthread_create(&m_keepalive, 0, conndbpool::KeepPoolAlive, this);
|
||||
if( nRet )
|
||||
{
|
||||
cerr << "Thread create failed.: errno: " << errno << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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
|
||||
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, conndbpool::POOL_FREE));
|
||||
}
|
||||
|
||||
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_poolmap.size();
|
||||
}
|
||||
|
||||
int conndbpool::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 == conndbpool::POOL_FREE || iter->second == conndbpool::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 == conndbpool::POOL_FREE)
|
||||
{
|
||||
DataBase *data = static_cast<DataBase *>(iter->first);
|
||||
delete (DataBase *) data;
|
||||
m_poolmap.f
|
||||
m_poolmap.erase(iter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return m_poolmap.size();
|
||||
}
|
||||
|
||||
DataBase * conndbpool::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() )
|
||||
{
|
||||
msg << "DB Pool empty.";
|
||||
LOGACERR(LERR, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if( iter == m_poolmap.end() )
|
||||
{
|
||||
iter = m_poolmap.begin();
|
||||
}
|
||||
|
||||
for( ; !m_poolmap.empty()&& iter != m_poolmap.end(); )
|
||||
{
|
||||
if(iter->second == conndbpool::POOL_FREE)
|
||||
{
|
||||
iter->second = conndbpool::POOL_USE;
|
||||
r = iter->first;
|
||||
m_lastset = r;
|
||||
break;
|
||||
}
|
||||
else if (iter->second == conndbpool::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.";
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
|
||||
if( out > 0 )
|
||||
{
|
||||
usetime += GET_SLEEP;
|
||||
|
||||
if(usetime > out)
|
||||
{
|
||||
msg << "GetConnFromPool Timeout." << usetime << "," << out <<
|
||||
"," << time(NULL) -t;
|
||||
LOGACERR(LERR, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (r == NULL);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void conndbpool::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==conndbpool::POOL_USE)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
iter->second=conndbpool::POOL_FREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream msg;
|
||||
iter->second=conndbpool::POOL_ERR;
|
||||
msg << "DB Pool used failed.";
|
||||
LOGACERR(LERR, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool conndbpool::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 conndbpool::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 == conndbpool::POOL_FREE)
|
||||
{
|
||||
iter->second = conndbpool::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();
|
||||
LOGACERR(LERR, msg);
|
||||
iter->second=conndbpool::POOL_ERR;
|
||||
iter++;
|
||||
//m_poolmap.erase(iter++);
|
||||
//delete d;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->second = conndbpool::POOL_FREE;
|
||||
msg << "Send alive : message success.";
|
||||
_LOGACOUT(LDBG, msg);
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
else if (iter->second == conndbpool::POOL_ERR)
|
||||
{
|
||||
msg << "Send alive : Error Pool remove.";
|
||||
_LOGACOUT(LDBG, msg);
|
||||
m_poolmap.erase(iter++);
|
||||
delete d;
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* conndbpool::KeepPoolAlive( void* pdata )
|
||||
{
|
||||
conndbpool* pObject = reinterpret_cast<conndbpool *>(pdata);
|
||||
ostringstream msg;
|
||||
|
||||
while( pObject->IsExit() == false )
|
||||
{
|
||||
bool b = pObject->IsTimeoutAlive();
|
||||
msg << "KeepPoolAlive Timeout - run : " << b;
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
if( pObject->IsExit() == false && b )
|
||||
{
|
||||
// send keep alive message
|
||||
pObject->SendAliveMsg();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conndbpool::SetKeepAliveTimeout(int sec)
|
||||
{
|
||||
m_alivetime = sec;
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
return m_alivetime;
|
||||
}
|
||||
|
||||
int conndbpool::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 == conndbpool::POOL_FREE)
|
||||
{
|
||||
r++;
|
||||
}
|
||||
}
|
||||
// pthread_mutex_unlock(&m_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
// 2014.06.06 dadamin
|
||||
// 현재 DB 형상 체크
|
||||
bool conndbpool::SetTargetTableType(DataBase * d)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
if (d == NULL)
|
||||
return false;
|
||||
|
||||
d->PgDoExec("SELECT * FROM pg_tables WHERE schemaname = 'public' AND tablename = 't_dav_resource'");
|
||||
if (d->PgResult(DataBase::NOT_CLEAR) < 0)
|
||||
{
|
||||
d->PgClear();
|
||||
msg << "SetTargetTableType failed : " << d->GetErrorMessage();
|
||||
LOGACERR(LERR, msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d->GetNoTuples() > 0)
|
||||
{
|
||||
m_tabletype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tabletype = 1;
|
||||
}
|
||||
|
||||
d->PgClear();
|
||||
msg << "Set Target Table Type : " << m_tabletype;
|
||||
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 작업할 메타 테이블명
|
||||
string conndbpool::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 conndbpool::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 == conndbpool::POOL_FREE)
|
||||
{
|
||||
f++;
|
||||
}
|
||||
else
|
||||
{
|
||||
u++;
|
||||
}
|
||||
}
|
||||
|
||||
ostringstream msg;
|
||||
if( prefixed.empty() == false )
|
||||
msg << "["<< prefixed <<"]";
|
||||
|
||||
msg <<"DB connection Pool - " <<"total : " << m_poolmap.size() << "(" << u <<
|
||||
"/" << f << ")";
|
||||
|
||||
_LOGACOUT(LINF, msg);
|
||||
}
|
||||
|
||||
// master db pool
|
||||
masterdbpool::masterdbpool(databaseinfo info)
|
||||
: conndbpool(info)
|
||||
{
|
||||
}
|
||||
|
||||
masterdbpool::~masterdbpool()
|
||||
{
|
||||
}
|
||||
|
||||
void masterdbpool::init(databaseinfo info)
|
||||
{
|
||||
if( masterdbpool::m_inst == NULL )
|
||||
{
|
||||
masterdbpool::m_inst = new masterdbpool(info);
|
||||
}
|
||||
}
|
||||
|
||||
masterdbpool* masterdbpool::getInstance()
|
||||
{
|
||||
return masterdbpool::m_inst;
|
||||
}
|
||||
|
||||
int masterdbpool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if( masterdbpool::m_inst != NULL )
|
||||
{
|
||||
r = masterdbpool::m_inst->DestroyPool();
|
||||
delete masterdbpool::m_inst;
|
||||
masterdbpool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// slave db pool
|
||||
slavedbpool::slavedbpool(databaseinfo info)
|
||||
: conndbpool(info)
|
||||
{
|
||||
}
|
||||
|
||||
slavedbpool::~slavedbpool()
|
||||
{
|
||||
}
|
||||
|
||||
void slavedbpool::init(databaseinfo info)
|
||||
{
|
||||
if( slavedbpool::m_inst == NULL )
|
||||
{
|
||||
slavedbpool::m_inst = new slavedbpool(info);
|
||||
}
|
||||
}
|
||||
|
||||
slavedbpool* slavedbpool::getInstance()
|
||||
{
|
||||
return slavedbpool::m_inst;
|
||||
}
|
||||
|
||||
int slavedbpool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if(slavedbpool::m_inst != NULL )
|
||||
{
|
||||
r = slavedbpool::m_inst->DestroyPool();
|
||||
delete slavedbpool::m_inst;
|
||||
slavedbpool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/***************************************************************************
|
||||
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__
|
||||
|
||||
class DataBase;
|
||||
|
||||
class conndbpool
|
||||
{
|
||||
public:
|
||||
enum POOL_STATUSE
|
||||
{
|
||||
POOL_ERR = -1,
|
||||
POOL_FREE = 0,
|
||||
POOL_USE = 1
|
||||
};
|
||||
public:
|
||||
conndbpool(databaseinfo info);
|
||||
virtual ~conndbpool();
|
||||
|
||||
int CreatePool( 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 SetDatabaseInfo(databaseinfo info) { m_dbinfo = info; }
|
||||
databaseinfo GetDatabaseInfo() { 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:
|
||||
databaseinfo 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;
|
||||
};
|
||||
|
||||
class masterdbpool : public conndbpool
|
||||
{
|
||||
public:
|
||||
static void init(databaseinfo info);
|
||||
static masterdbpool* getInstance();
|
||||
static int release();
|
||||
|
||||
private:
|
||||
masterdbpool(databaseinfo info);
|
||||
~masterdbpool();
|
||||
|
||||
private:
|
||||
static masterdbpool* m_inst;
|
||||
};
|
||||
|
||||
class slavedbpool : public conndbpool
|
||||
{
|
||||
public:
|
||||
static void init(databaseinfo info);
|
||||
static slavedbpool* getInstance();
|
||||
static int release();
|
||||
|
||||
private:
|
||||
slavedbpool(databaseinfo info);
|
||||
~slavedbpool();
|
||||
|
||||
private:
|
||||
static slavedbpool* m_inst;
|
||||
};
|
||||
|
||||
#endif // __DATABASE_CONNECTION_POOL__
|
||||
@@ -0,0 +1,349 @@
|
||||
/***************************************************************************
|
||||
Job Manager
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 "rc_cmove.h"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fstream>
|
||||
#include "jobmanager.h"
|
||||
#include "parameter.h"
|
||||
#include "workpool.h"
|
||||
#include "Logger.h"
|
||||
#include "dbconnpool.h"
|
||||
|
||||
#define WORK_WAIT 1000000 // microsecond
|
||||
|
||||
static int worknotifyfn(void *object , short success)
|
||||
{ jobmanager* manager = reinterpret_cast<jobmanager *>(object);
|
||||
ostringstream msg;
|
||||
msg << "Called worknotifyfn :" << success;
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
return manager->worknotify(success);
|
||||
}
|
||||
|
||||
jobmanager::jobmanager(JOB_TYPE::JOB_TYPE type, const char* syncpath)
|
||||
: m_type(type),m_exit(false)
|
||||
{
|
||||
m_tmppath.m_syncpath = syncpath;
|
||||
pthread_mutex_init(&m_notifymutex, NULL);
|
||||
}
|
||||
|
||||
jobmanager::~jobmanager()
|
||||
{
|
||||
pthread_mutex_destroy(&m_notifymutex);
|
||||
}
|
||||
|
||||
int jobmanager::run()
|
||||
{
|
||||
|
||||
int nRet = pthread_create(&m_hthread, 0, jobmanager::WorkFn, this);
|
||||
if( nRet )
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "Thread create failed.[" << errno << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool jobmanager::gettargethostlist(string path, vector<string> &vechost)
|
||||
{
|
||||
ostringstream msg;
|
||||
if(path.size() > 0 )
|
||||
{
|
||||
ifstream hostfile;
|
||||
hostfile.open(path.c_str());
|
||||
if( hostfile.is_open() == false )
|
||||
{
|
||||
msg << "Target Host file open error.[" << path << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
string line;
|
||||
while (!hostfile.eof() )
|
||||
{
|
||||
getline (hostfile,line);
|
||||
if(line.empty() == true || line == "\r")
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "host data read : empty or linefeed" << line << endl;
|
||||
#endif // _DEBUG
|
||||
continue;
|
||||
}
|
||||
|
||||
// check IP addres
|
||||
struct in_addr laddr;
|
||||
int status = inet_aton(line.c_str(), &laddr);
|
||||
if(status != 0)
|
||||
{
|
||||
msg << "Target Host Not DNS Name.['" << line << "' IN " << path << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
vechost.push_back(line);
|
||||
}
|
||||
|
||||
hostfile.close();
|
||||
if( vechost.size() == 0 )
|
||||
{
|
||||
msg << "Target Host file Empty.[" << path << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool jobmanager::runsync()
|
||||
{
|
||||
ostringstream msg;
|
||||
ifstream syncfile;
|
||||
|
||||
msg << "Job - Synchronize working...";
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
// target host list
|
||||
vector<string> hostlist;
|
||||
if( gettargethostlist(parameter::getInstance()->gettargetlistpath(), hostlist) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get sync file line
|
||||
m_status.m_diff = getfileline(m_tmppath.m_syncpath.c_str());
|
||||
|
||||
syncfile.open(m_tmppath.m_syncpath.c_str());
|
||||
|
||||
if( syncfile.is_open() == false )
|
||||
{
|
||||
msg << "Sync data file open error.[" << m_tmppath.m_syncpath <<"]";
|
||||
LOGACERR(LERR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
string line;
|
||||
while (!syncfile.eof() )
|
||||
{
|
||||
getline (syncfile,line);
|
||||
if(line.empty() == true || line == "\r")
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "Sync data read : empty or linefeed" << line << endl;
|
||||
#endif // _DEBUG
|
||||
if(!syncfile.eof())
|
||||
{
|
||||
++m_status.m_launcherfail;
|
||||
msg << "File Data Empty. or carriage return." << line;
|
||||
LOGACERR(LERR, msg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(m_exit)
|
||||
{
|
||||
msg << "Work force to end.";
|
||||
LOGACERR(LNOT, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
cout << "Sync data read : " << line << endl;
|
||||
#endif // _DEBUG
|
||||
work *w = workpool::getInstance()->GetWorkPool();
|
||||
if(w != NULL )
|
||||
{
|
||||
++m_status.m_work;
|
||||
w->setenablesync("1111");
|
||||
w->setnetworkmode(parameter::getInstance()->getnetworkmode());
|
||||
if( hostlist.size() > 0 )
|
||||
w->settargethost(hostlist);
|
||||
w->run(m_type,line,worknotifyfn, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
++m_status.m_launcherfail;
|
||||
msg << "Get Work Pool error :" << line;
|
||||
LOGACERR(LERR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
// 마지막 라인에 캐리지 리턴 없는 경우 파일을 실제 읽었을 때보다
|
||||
// 한라인 작은 수를 wc -l 에서 출력되어 작업이 완료되지 않는 것을
|
||||
// 막기 위해서 work가 diff 값보다 클 때 diff 값을 work 값으로 보정
|
||||
if (m_status.m_diff < m_status.m_work)
|
||||
m_status.m_diff = m_status.m_work;
|
||||
|
||||
syncfile.close();
|
||||
|
||||
msg << "Job - Synchronize working End";
|
||||
_LOGACOUT(LINF, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
void jobmanager::cleandata()
|
||||
{
|
||||
/*
|
||||
// delete temp file
|
||||
#ifndef _DEBUG
|
||||
unlink(m_tmppath.m_msrcpath.c_str());
|
||||
unlink(m_tmppath.m_ssrcpath.c_str());
|
||||
unlink(m_tmppath.m_diffpath.c_str());
|
||||
unlink(m_tmppath.m_syncpath.c_str());
|
||||
#endif // _DEBUG
|
||||
|
||||
// delete memory
|
||||
while( m_srcdata.size() > 0 )
|
||||
{
|
||||
vector<CSourceData*>::iterator iter = m_srcdata.begin();
|
||||
m_srcdata.erase(iter);
|
||||
delete static_cast<CSourceData *>(*iter);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void jobmanager::cleanup( void* pdata )
|
||||
{
|
||||
jobmanager* pObject = reinterpret_cast<jobmanager *>(pdata);
|
||||
#ifdef _DEBUG
|
||||
cout << "Job cleanup thread:" << pthread_self() << endl;
|
||||
#endif // _DEBUG
|
||||
pObject->cleandata();
|
||||
}
|
||||
|
||||
void* jobmanager::WorkFn( void* pdata )
|
||||
{
|
||||
jobmanager* pObject = reinterpret_cast<jobmanager *>(pdata);
|
||||
|
||||
ostringstream msg;
|
||||
msg << "Job Manager thread start [" << "???" << "]";
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
|
||||
pthread_cleanup_push(jobmanager::cleanup, pdata);
|
||||
|
||||
bool running = true;
|
||||
while(running)
|
||||
{
|
||||
// sync
|
||||
pObject->runsync();
|
||||
|
||||
// waiting
|
||||
pObject->waiting();
|
||||
|
||||
running = false;
|
||||
}
|
||||
|
||||
msg << "Job Manager thread end[" << "???" << "]";
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jobmanager::worknotify(short success)
|
||||
{
|
||||
ostringstream msg;
|
||||
pthread_mutex_lock(&m_notifymutex);
|
||||
|
||||
msg << "work notify :" << success;
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
|
||||
if (success == 0)
|
||||
++m_status.m_success;
|
||||
else
|
||||
++m_status.m_error;
|
||||
|
||||
if(success != 0)
|
||||
{
|
||||
if( masterdbpool::getInstance()->GetPoolSize() == 0 )
|
||||
{
|
||||
msg << "Master DB Pool empty. And Work force to end.";
|
||||
LOGACERR(LDEV1, msg);
|
||||
m_exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_notifymutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t jobmanager::getfileline(const char* path)
|
||||
{
|
||||
int64_t r = 0;
|
||||
ostringstream cmd, msg;
|
||||
|
||||
cmd << "cat " << path << " | wc -l";
|
||||
string lines = getCommand(cmd.str());
|
||||
|
||||
//msg << "file lines : CMD - " << cmd.str() << " => " << lines;
|
||||
//_LOGACOUT(LDBG,msg);
|
||||
|
||||
r = atoll(lines.c_str());
|
||||
msg << "file lines : " << path << " => " << r;
|
||||
_LOGACOUT(LDBG,msg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool jobmanager::waiting()
|
||||
{
|
||||
bool r = true;
|
||||
ostringstream msg;
|
||||
do
|
||||
{
|
||||
if (m_status.m_diff ==
|
||||
(m_status.m_error + m_status.m_success + m_status.m_launcherfail) )
|
||||
{
|
||||
msg << "work end of waiting";
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
printstatus();
|
||||
break;
|
||||
}
|
||||
|
||||
if( (m_exit) &&(m_status.m_work == (m_status.m_error + m_status.m_success)) )
|
||||
{
|
||||
msg << "Work force to end.";
|
||||
LOGACERR(LNOT, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
msg << "work of waiting.........";
|
||||
_LOGACOUT(LDBG, msg);
|
||||
printstatus();
|
||||
#endif // _DEBUG
|
||||
|
||||
solusleep(WORK_WAIT);
|
||||
}while(true);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void jobmanager::printstatus(string prefixed)
|
||||
{
|
||||
ostringstream msg;
|
||||
if( prefixed.empty() == false )
|
||||
msg << "[" << prefixed << "]";
|
||||
|
||||
msg << "Job Manager(" << "???" << "=>" << "!!!" <<
|
||||
") total : " << m_status.m_diff << "(R" << m_status.m_work << "/F" <<
|
||||
m_status.m_launcherfail <<"), result :S" << m_status.m_success << "/E" << m_status.m_error;
|
||||
|
||||
_LOGACOUT(LINF, msg);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
Job Manager
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 __JOBMANAGER_H__
|
||||
#define __JOBMANAGER_H__
|
||||
|
||||
class CSourceData;
|
||||
|
||||
class jobmanager
|
||||
{
|
||||
public:
|
||||
jobmanager(JOB_TYPE::JOB_TYPE type, const char* syncpath);
|
||||
~jobmanager();
|
||||
|
||||
int run();
|
||||
|
||||
bool runsync();
|
||||
|
||||
pthread_t getjobhandle() {return m_hthread;}
|
||||
|
||||
void setexit(bool v) { m_exit = v; }
|
||||
bool isexit() { return m_exit; }
|
||||
void setsyncfilename(const char* path) {m_tmppath.m_syncpath = path; }
|
||||
string getsyncfilenmae() { return m_tmppath.m_syncpath; }
|
||||
|
||||
int worknotify(short success);
|
||||
|
||||
void printstatus(string prefixed = "");
|
||||
|
||||
private:
|
||||
static void* WorkFn(void* pdata);
|
||||
static void cleanup(void* pdata);
|
||||
|
||||
void cleandata();
|
||||
|
||||
bool gettargethostlist(string path, vector<string> &vechost);
|
||||
bool waiting();
|
||||
|
||||
int64_t getfileline(const char* path);
|
||||
|
||||
private:
|
||||
//*
|
||||
class tmpdataspath
|
||||
{
|
||||
public:
|
||||
string m_syncpath;
|
||||
};
|
||||
|
||||
class jobstatus
|
||||
{
|
||||
public:
|
||||
jobstatus()
|
||||
: 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;
|
||||
};
|
||||
|
||||
JOB_TYPE::JOB_TYPE m_type;
|
||||
tmpdataspath m_tmppath;
|
||||
jobstatus m_status;
|
||||
|
||||
bool m_exit;
|
||||
|
||||
pthread_t m_hthread;
|
||||
vector<CSourceData*> m_srcdata;
|
||||
|
||||
pthread_mutex_t m_notifymutex;
|
||||
};
|
||||
|
||||
#endif // __JOBMANAGER_H__
|
||||
@@ -0,0 +1,293 @@
|
||||
#include "rc_cmove.h"
|
||||
#include "Logger.h"
|
||||
#include "parameter.h"
|
||||
#include "dbconnpool.h"
|
||||
#include "workpool.h"
|
||||
#include "jobmanager.h"
|
||||
#include "monitoring.h"
|
||||
#include "RcSyncdRequest.h"
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define DBPOOL_KEEPALIVE_TIMEOUT 10 // 10 sec
|
||||
#else // !_DEBUG
|
||||
#define DBPOOL_KEEPALIVE_TIMEOUT 300 // 30 min
|
||||
#endif // _DEBUG
|
||||
|
||||
static bool _bexit = false;
|
||||
|
||||
static void SigTermMain( int nSignalNumber )
|
||||
{
|
||||
ostringstream msg;
|
||||
if( _bexit == true )
|
||||
return;
|
||||
|
||||
_bexit= true;
|
||||
// Signal Number 에 따른 로깅처리.
|
||||
if( nSignalNumber == SIGTERM )
|
||||
{
|
||||
msg << "Main Process exit job start by user signal [SIGTERM]";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "Main Process exit job start by user signal ["<< nSignalNumber <<"]";
|
||||
}
|
||||
// Process 종료관련 작업 추가
|
||||
LOGACERR(LWAR, msg);
|
||||
|
||||
// waitpid
|
||||
while(waitpid(-1, NULL, WNOHANG) > 0);
|
||||
//g_pLog = NULL;
|
||||
|
||||
solusleep(500000);
|
||||
|
||||
// end
|
||||
monitoring::getInstance()->release();
|
||||
exit( EXIT_SUCCESS );
|
||||
}
|
||||
|
||||
// signal
|
||||
static void SetSignalMain()
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction act;
|
||||
sigfillset( &set );
|
||||
sigprocmask( SIG_SETMASK, &set, NULL );
|
||||
memset( &act, 0x00, sizeof(act) );
|
||||
sigfillset( &act.sa_mask );
|
||||
/* 무시할 신호 목록 */
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
|
||||
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
|
||||
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
|
||||
|
||||
// Child Process 종료에 대한 처리기 설정.
|
||||
//act.sa_handler = sigchld_hdl;
|
||||
//sigaction( SIGCHLD, &act, NULL);
|
||||
/* 각종 에러나 사용자의 종료 신호 처리 */
|
||||
act.sa_handler = SigTermMain;
|
||||
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
|
||||
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => kill -TERM 과 동일한 처리함 */
|
||||
|
||||
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
|
||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||
}
|
||||
|
||||
// mode sync
|
||||
void chksync()
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "Mode Sync Check...";
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
string service = parameter::getInstance()->getservice();
|
||||
string sdate = parameter::getInstance()->getsyncstart();
|
||||
string edate = parameter::getInstance()->getsyncend();
|
||||
|
||||
if (sdate.empty() || edate.empty())
|
||||
{
|
||||
msg << "Empty date.(-p start_date:end_date) " << service;
|
||||
_LOGACERR(LERR, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
msg << "START SYNC CHECK: " << service;
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
if (sdate.compare(edate) > 0)
|
||||
{
|
||||
msg << "Start time is greater than End time.";
|
||||
_LOGACERR(LERR, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
SYNC_TYPE::SYNC_TYPE synct = SYNC_TYPE::CHK_ONLY_N_ONLY;
|
||||
|
||||
if (parameter::getInstance()->includdel())
|
||||
synct = SYNC_TYPE::CHK_ONLY;
|
||||
|
||||
// sync 요청 처리
|
||||
// scheduler -> rc_syncd (local host)
|
||||
// 성공 실패 여부는 objRcSyncdRequest 객체 내부에서 로깅 처리 함.
|
||||
CRcSyncdRequest objRcSyncdRequest;
|
||||
|
||||
if (service.empty())
|
||||
{
|
||||
objRcSyncdRequest.SendSyncRequest(synct, sdate, edate);
|
||||
}
|
||||
else
|
||||
{
|
||||
objRcSyncdRequest.SendSyncRequest(synct, sdate, edate, service);
|
||||
}
|
||||
}
|
||||
|
||||
msg << "END SYNC CHECK: " << service;
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
}
|
||||
|
||||
// mode copy and move
|
||||
void copyamove(JOB_TYPE::JOB_TYPE type)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
string mode = (type == JOB_TYPE::COPY ? MODE_COPY : MODE_MOVE);
|
||||
|
||||
// create DB connection
|
||||
masterdbpool::init(parameter::getInstance()->getdbinfo(parameter::MASTER));
|
||||
if (masterdbpool::getInstance()->CreatePool(
|
||||
parameter::getInstance()->getdbpoolcnt(parameter::MASTER)) <= 0)
|
||||
{
|
||||
msg << "database connection pool created fail(Master).";
|
||||
LOGACERR(LERR, msg);
|
||||
return ;
|
||||
}
|
||||
|
||||
masterdbpool::getInstance()->SetKeepAliveTimeout(DBPOOL_KEEPALIVE_TIMEOUT);
|
||||
|
||||
// create work pool
|
||||
if (workpool::getInstance()->CreatePool(parameter::getInstance()->getworkpoolcnt()) != 0)
|
||||
{
|
||||
cerr << "work pool created fail." << endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
msg << "RCDB : ";
|
||||
msg << (masterdbpool::getInstance()->UseDisplayname() ? "NEW" : "OLD");
|
||||
msg << " Type.";
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
msg << "Mode " << mode << "...";
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
string syncfilepath = parameter::getInstance()->getsyncpath();
|
||||
|
||||
if (syncfilepath.empty())
|
||||
{
|
||||
msg << "Not found sync file. and re-run -f [sync file]" << syncfilepath;
|
||||
_LOGACERR(LERR, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
msg << "START : sync path = " << syncfilepath;
|
||||
_LOGACOUT(LINF, msg);
|
||||
|
||||
vector<jobmanager *> jobs;
|
||||
jobmanager *newjob = new jobmanager(type, syncfilepath.c_str());
|
||||
if (newjob->run() == 0)
|
||||
{
|
||||
jobs.push_back(newjob);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete newjob;
|
||||
}
|
||||
|
||||
if (jobs.size() == 0)
|
||||
{
|
||||
msg << "sync job empty.";
|
||||
_LOGACERR(LERR, msg);
|
||||
}
|
||||
|
||||
// set monitoring
|
||||
monitoring::getInstance()->setjobs(&jobs);
|
||||
|
||||
// wait job end
|
||||
int rc;
|
||||
while (jobs.size() > 0)
|
||||
{
|
||||
jobmanager *job = static_cast<jobmanager *> (*jobs.begin());
|
||||
#ifdef _DEBUG
|
||||
cout << "Wait Job...." << endl;
|
||||
#endif // _DEBUG
|
||||
rc = pthread_join(job->getjobhandle(), NULL);
|
||||
if (rc == 0)
|
||||
{
|
||||
monitoring::getInstance()->monlock();
|
||||
job->setexit(true);
|
||||
jobs.erase(jobs.begin());
|
||||
delete job;
|
||||
job = NULL;
|
||||
if (jobs.empty())
|
||||
monitoring::getInstance()->setexit();
|
||||
monitoring::getInstance()->monunlock();
|
||||
}
|
||||
}
|
||||
|
||||
msg << "END : sync file = " << syncfilepath;
|
||||
|
||||
|
||||
if (type == JOB_TYPE::COPY)
|
||||
{
|
||||
unlink(syncfilepath.c_str());
|
||||
}
|
||||
|
||||
_LOGACOUT(LINF, msg);
|
||||
}
|
||||
|
||||
// main function
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
// setting signal
|
||||
SetSignalMain();
|
||||
|
||||
// argument to data
|
||||
if( parameter::getInstance()->argvtoparam(argc, argv) == false )
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// load config
|
||||
if( parameter::getInstance()->loadconf() == false )
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// log init
|
||||
if( CLogger::Init( PROG_NAME, parameter::getInstance()->getlogpath(),
|
||||
parameter::getInstance()->getloglevel() ) == false )
|
||||
{
|
||||
cerr << "Logger init failed." << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// monitoring init
|
||||
if( monitoring::getInstance()->init() == false)
|
||||
{
|
||||
cerr << "monitoring created fail." << endl;
|
||||
}
|
||||
|
||||
// work
|
||||
bool runfail = false;
|
||||
string mode = parameter::getInstance()->getsyncmode();
|
||||
if (mode.compare(MODE_SYNC) == 0)
|
||||
{
|
||||
chksync();
|
||||
}
|
||||
else if (mode.compare(MODE_COPY) == 0)
|
||||
{
|
||||
copyamove(JOB_TYPE::COPY);
|
||||
}
|
||||
else if (mode.compare(MODE_MOVE) == 0)
|
||||
{
|
||||
copyamove(JOB_TYPE::MOVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
runfail = true;
|
||||
msg << "This mode is not supported.[-m " << mode << "]";
|
||||
_LOGACOUT(LERR, msg);
|
||||
}
|
||||
|
||||
// end
|
||||
if (workpool::getInstance())
|
||||
workpool::getInstance()->release();
|
||||
|
||||
if (masterdbpool::getInstance())
|
||||
masterdbpool::getInstance()->release();
|
||||
|
||||
if (monitoring::getInstance())
|
||||
monitoring::getInstance()->release();
|
||||
parameter::getInstance()->release();
|
||||
|
||||
CLogger::Exit();
|
||||
return (runfail ? EXIT_FAILURE: EXIT_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/***************************************************************************
|
||||
Monitoring
|
||||
-----------------------------------------
|
||||
begin : 2015/05/14
|
||||
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 "rc_cmove.h"
|
||||
#include "monitoring.h"
|
||||
#include "dbconnpool.h"
|
||||
#include "workpool.h"
|
||||
#include "jobmanager.h"
|
||||
#include "Logger.h"
|
||||
|
||||
|
||||
#define MONITORING_SLEEP (1000*1000) // microsecond
|
||||
|
||||
monitoring *monitoring::m_inst = NULL;
|
||||
|
||||
monitoring::monitoring()
|
||||
: m_exit(false), m_pjobs(NULL)
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
}
|
||||
|
||||
monitoring::~monitoring()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
}
|
||||
|
||||
void* monitoring::monitoringfn( void* pdata )
|
||||
{
|
||||
monitoring* pObject = reinterpret_cast<monitoring *>(pdata);
|
||||
ostringstream msg;
|
||||
|
||||
//pthread_detach(pthread_self());
|
||||
|
||||
msg << "monitoring::monitoringfn Start";
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
while( pObject->m_exit == false )
|
||||
{
|
||||
msg << "monitoring::monitoringfn";
|
||||
_LOGACOUT(LDBG, msg);
|
||||
// pool status
|
||||
if (masterdbpool::getInstance())
|
||||
masterdbpool::getInstance()->printstatus("monitoring");
|
||||
|
||||
//slavedbpool::getInstance()->printstatus("monitoring(Slave)");
|
||||
if (workpool::getInstance())
|
||||
workpool::getInstance()->printstatus("monitoring");
|
||||
|
||||
if( CLogger::GetInstance()->GetLogLevel() >= LDEV1 )
|
||||
workpool::getInstance()->printstatusex("monitoring-DEBUG");
|
||||
|
||||
// job status
|
||||
if (pObject->m_exit == false)
|
||||
{
|
||||
pObject->printjobstatus("monitoring");
|
||||
solusleep(MONITORING_SLEEP);
|
||||
}
|
||||
}
|
||||
|
||||
msg << "monitoring::monitoringfn End";
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool monitoring::init()
|
||||
{
|
||||
|
||||
// Monitoring thread
|
||||
int nRet = pthread_create(&m_thread, 0, monitoring::monitoringfn, this);
|
||||
if( nRet )
|
||||
{
|
||||
cerr << "Thread create failed.: errno: " << errno << endl;
|
||||
return false;
|
||||
}
|
||||
sleep(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void monitoring::destory()
|
||||
{
|
||||
m_exit = true;
|
||||
pthread_join(m_thread, NULL);
|
||||
}
|
||||
|
||||
monitoring* monitoring::getInstance()
|
||||
{
|
||||
if(monitoring::m_inst == NULL)
|
||||
{
|
||||
monitoring::m_inst = new monitoring();
|
||||
}
|
||||
|
||||
return monitoring::m_inst;
|
||||
}
|
||||
|
||||
void monitoring::release()
|
||||
{
|
||||
if( monitoring::m_inst != NULL)
|
||||
{
|
||||
monitoring::m_inst->destory();
|
||||
delete monitoring::m_inst;
|
||||
monitoring::m_inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void monitoring::printjobstatus(string prefixed)
|
||||
{
|
||||
if (m_exit) return;
|
||||
|
||||
ostringstream msg;
|
||||
if( m_pjobs == NULL )
|
||||
{
|
||||
msg << "monitoring - Work has not been set yet.";
|
||||
_LOGACOUT(LDBG, msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
monlock();
|
||||
vector<jobmanager *>::iterator it;
|
||||
if (m_pjobs->size())
|
||||
{
|
||||
for (it = m_pjobs->begin(); it < m_pjobs->end(); it++)
|
||||
{
|
||||
if (m_exit == false && it != m_pjobs->end())
|
||||
{
|
||||
if ((*it)->isexit() == false)
|
||||
(*it)->printstatus(prefixed);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
monunlock();
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
Monitoring
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 __MONITORING__
|
||||
#define __MONITORING__
|
||||
|
||||
class jobmanager;
|
||||
|
||||
class monitoring
|
||||
{
|
||||
public:
|
||||
static monitoring* getInstance();
|
||||
static void release();
|
||||
|
||||
bool init();
|
||||
void destory();
|
||||
|
||||
void setjobs(vector<jobmanager *> *p) { m_pjobs = p; }
|
||||
void setexit() { m_exit = true; }
|
||||
|
||||
void monlock() { pthread_mutex_lock(&m_mutex); }
|
||||
void monunlock() { pthread_mutex_unlock(&m_mutex); }
|
||||
|
||||
private:
|
||||
monitoring();
|
||||
virtual ~monitoring();
|
||||
|
||||
void printjobstatus(string prefixed = "");
|
||||
|
||||
static void* monitoringfn(void * pdata);
|
||||
|
||||
private:
|
||||
static monitoring* m_inst;
|
||||
pthread_t m_thread;
|
||||
bool m_exit;
|
||||
vector<jobmanager *> *m_pjobs;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
};
|
||||
|
||||
#endif // __MONITORING__
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
/***************************************************************************
|
||||
Parameter
|
||||
-----------------------------------------
|
||||
begin : 2015/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 "rc_cmove.h"
|
||||
#include "parameter.h"
|
||||
#include "Config.h"
|
||||
|
||||
#define REPORT_NAME "report"
|
||||
#define MAX_DB_POOL 10
|
||||
#define DEFAULT_FHS_MOUNT "/stg/node0,/stg/node1,/stg/node2"
|
||||
|
||||
parameter *parameter::inst = NULL;
|
||||
|
||||
parameter::parameter()
|
||||
:m_confpath(DEFAULT_CONFIG_FILE), m_networkmode(1), m_includedel(false)
|
||||
{
|
||||
}
|
||||
|
||||
parameter::~parameter()
|
||||
{
|
||||
}
|
||||
|
||||
parameter* parameter::getInstance()
|
||||
{
|
||||
if( parameter::inst == NULL )
|
||||
{
|
||||
parameter::inst = new parameter;
|
||||
}
|
||||
|
||||
return parameter::inst;
|
||||
}
|
||||
|
||||
void parameter::release()
|
||||
{
|
||||
if( parameter::inst != NULL )
|
||||
{
|
||||
delete parameter::inst;
|
||||
parameter::inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void parameter::printusage()
|
||||
{
|
||||
cerr << "usage: " << PROG_NAME << " [-v] [-m mode] ([-f path] [-t path] ";
|
||||
cerr << "([-n mode])) ([-p starttime:endtime] [-d] [-s service sequence])";
|
||||
cerr << endl;
|
||||
}
|
||||
|
||||
bool parameter::argvtoparam( int argc, char * const argv[] )
|
||||
{
|
||||
int o;
|
||||
|
||||
if( argc == 1 )
|
||||
{
|
||||
cerr << "Invalid input arguments." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((o = getopt(argc, argv, "vf:n:t:c:m:p:s:d")) >= 0)
|
||||
{
|
||||
switch (o)
|
||||
{
|
||||
case 'v': // version info
|
||||
cerr << "[info] " << PROG_NAME << " Version : " << PROG_VERSION << endl;
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
// use common
|
||||
case 'm':// mode
|
||||
m_mode = optarg;
|
||||
break;
|
||||
case 'c': // config path
|
||||
m_confpath = optarg;
|
||||
break;
|
||||
// use move & use copy
|
||||
case 'f': // transfer list path
|
||||
{
|
||||
if (issyncmode())
|
||||
{
|
||||
cerr << "'-f' Available copy or move mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_synclistpath = optarg;
|
||||
}
|
||||
break;
|
||||
case 't': // host list path
|
||||
{
|
||||
if (issyncmode())
|
||||
{
|
||||
cerr << "'-t' Available copy or move mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
m_targetlistpath = optarg;
|
||||
}
|
||||
break;
|
||||
// use move
|
||||
case 'n': // network mode
|
||||
{
|
||||
if (ismovemode() == false)
|
||||
{
|
||||
cerr << "'-n' Available only move mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_networkmode = atoi(optarg);
|
||||
}
|
||||
break;
|
||||
//use sync
|
||||
case 'p':
|
||||
{
|
||||
if (issyncmode() == false)
|
||||
{
|
||||
cerr << "'-p' Available only sync mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
string t = optarg;
|
||||
StringSplit(t, ":", m_synctime);
|
||||
|
||||
if (m_synctime.size() != 2)
|
||||
{
|
||||
cerr << "The request does not fit the format. [-p starttime:endtime]";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
if (issyncmode() == false)
|
||||
{
|
||||
cerr << "'-s' Available only sync mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_service = optarg;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
if (issyncmode() == false)
|
||||
{
|
||||
cerr << "'-d' Available only sync mode.";
|
||||
cerr << endl;
|
||||
return false;
|
||||
}
|
||||
m_includedel = true;
|
||||
}
|
||||
break;
|
||||
default: // unknown
|
||||
#ifdef _DEBUG
|
||||
cout << "unknown arguments." << endl;
|
||||
#endif // _DEBUG
|
||||
printusage();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mode.empty())
|
||||
{
|
||||
printusage();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parameter::loadconf()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "conf :" << m_confpath << endl;
|
||||
#endif // _DEBUG
|
||||
Config conf;
|
||||
|
||||
// Config File open
|
||||
if( conf.Open(m_confpath) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string szValue;
|
||||
|
||||
// log path
|
||||
if( getconfdata( conf, "DEFAULT_LOG_DIR" ,szValue, true ) == false )
|
||||
return false;
|
||||
m_logpath = szValue;
|
||||
m_logreport = m_logpath + "/" + REPORT_NAME;
|
||||
|
||||
// log level
|
||||
if( getconfdata( conf, "LOG_LEVEL" ,szValue, true ) == false )
|
||||
return false;
|
||||
m_loglevel = atoi(szValue.c_str());
|
||||
|
||||
// work pool
|
||||
if( getconfdata( conf, "WORK_POOL" ,szValue, false ) == false )
|
||||
return false;
|
||||
m_workpoolcnt = atoi(szValue.c_str());
|
||||
|
||||
// skip keyword
|
||||
getconfdata(conf, "SKIP_KEYWORD", m_skipkey, true, false);
|
||||
//if( getconfdata(conf, "SKIP_KEYWORD", m_skipkey, false) == false )
|
||||
// return false;
|
||||
|
||||
databaseinfo m;
|
||||
// RCDB Information
|
||||
// master
|
||||
if( getconfdbinof(conf, parameter::MASTER, m) == false )
|
||||
return false;
|
||||
|
||||
m_dbinfo.push_back(m);
|
||||
|
||||
// DB Connection pool
|
||||
int pool = 0;
|
||||
getconfdata(conf, "DB_POOL", szValue, false);
|
||||
pool = atoi(szValue.c_str());
|
||||
m_dbpoolcnt.push_back(pool);
|
||||
|
||||
|
||||
if( 1 > m_dbpoolcnt[0] || m_dbpoolcnt[0] > MAX_DB_POOL )
|
||||
m_dbpoolcnt[0] = 4;
|
||||
|
||||
// FHS_STORAGE_MOUNT
|
||||
if (getconfdata(conf, "FHS_STORAGE_MOUNT", m_fhsmount, true, false) == false)
|
||||
{
|
||||
StringSplit(DEFAULT_FHS_MOUNT, ",", m_fhsmount);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parameter::getconfdbinof(Config &conf,int dbinfotype, databaseinfo &data)
|
||||
{
|
||||
bool bcommon = true;
|
||||
string szValue, szkey, szextkey;
|
||||
|
||||
switch(dbinfotype)
|
||||
{
|
||||
case parameter::MASTER:
|
||||
szextkey = "";
|
||||
bcommon = true;
|
||||
break;
|
||||
case parameter::SLAVE_FIRST:
|
||||
szextkey = "_SLAVE_FIRST";
|
||||
bcommon = false;
|
||||
break;
|
||||
case parameter::SLAVE_SECOND:
|
||||
szextkey = "_SLAVE_SECOND";
|
||||
bcommon = false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// db host
|
||||
szValue.clear();
|
||||
szkey = "RCDB_IP"+ szextkey;
|
||||
if( getconfdata( conf, szkey, szValue, bcommon) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data.m_hostaddr = szValue;
|
||||
|
||||
// db port
|
||||
szValue.clear();
|
||||
szkey = "RCDB_PORT"+ szextkey;
|
||||
if( getconfdata( conf, szkey, szValue, bcommon) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data.m_port = atoi(szValue.c_str());
|
||||
|
||||
// db database name
|
||||
szValue.clear();
|
||||
szkey = "RCDB_DB_NAME"+ szextkey;
|
||||
if( getconfdata( conf, szkey, szValue, bcommon) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data.m_dbname = szValue;
|
||||
|
||||
// db user
|
||||
szValue.clear();
|
||||
szkey = "RCDB_ACCT"+ szextkey;
|
||||
if( getconfdata( conf, szkey, szValue, bcommon) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data.m_user = szValue;
|
||||
|
||||
// db password
|
||||
szValue.clear();
|
||||
szkey = "RCDB_ACCT_PW"+ szextkey;
|
||||
if( getconfdata( conf, szkey, szValue, bcommon) == false )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
data.m_pw = szValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parameter::getconfdata(Config &conf, const string& key, string& value, bool bcommon /* = false */, bool returnerr /*= true*/)
|
||||
{
|
||||
value.clear();
|
||||
string prefix = "[error]";
|
||||
|
||||
if (returnerr == false)
|
||||
prefix = "[warning]";
|
||||
|
||||
if( conf.GetConfig( PROG_NAME, key, value ) == false )
|
||||
{
|
||||
if(bcommon == false)
|
||||
{
|
||||
cerr << prefix << " Config info get failed. [" << PROG_NAME << "]->" << key << endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( conf.GetConfig( "COMMON", key, value ) == false )
|
||||
{
|
||||
cerr << prefix << " Config info get failed. [COMMON]->" << key << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parameter::getconfdata(Config &conf, const string& key, vector< string >& value, bool bcommon /*= false */, bool returnerr /*= true*/)
|
||||
{
|
||||
value.clear();
|
||||
|
||||
string prefix = "[error]";
|
||||
if (returnerr == false)
|
||||
prefix = "[warning]";
|
||||
|
||||
if( conf.GetConfig( PROG_NAME, key, value ) == false )
|
||||
{
|
||||
if(bcommon == false)
|
||||
{
|
||||
cerr << prefix << " Config info get failed. [" << PROG_NAME << "]->" << key << endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( conf.GetConfig( "COMMON", key, value ) == false )
|
||||
{
|
||||
cerr << prefix << " Config info get failed. [COMMON]->" << key << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void parameter::print_loginfo()
|
||||
{
|
||||
cout << "Log Path : " << m_logpath << "/"<< PROG_NAME << "/" << endl;
|
||||
cout << "Log Level : " << m_loglevel <<endl;
|
||||
}
|
||||
|
||||
void parameter::print_dbinfo()
|
||||
{
|
||||
databaseinfo m = getdbinfo(parameter::MASTER);
|
||||
cout << "Master DB : " << m.m_hostaddr << "," << m.m_port << "," <<
|
||||
m.m_dbname << "," << m.m_user << "," << m.m_pw <<endl ;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/***************************************************************************
|
||||
Parameter
|
||||
-----------------------------------------
|
||||
begin : 2015/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 __PARAMETER_H__
|
||||
#define __PARAMETER_H__
|
||||
|
||||
class Config;
|
||||
|
||||
class parameter
|
||||
{
|
||||
public:
|
||||
enum DBINF0_TYPE {
|
||||
MASTER = 0,
|
||||
SLAVE_FIRST = 1,
|
||||
SLAVE_SECOND = 2
|
||||
};
|
||||
|
||||
private:
|
||||
static parameter *inst;
|
||||
string m_confpath;
|
||||
|
||||
// use common
|
||||
string m_mode;
|
||||
string m_synclistpath;
|
||||
string m_targetlistpath;
|
||||
|
||||
// use move mode
|
||||
int m_networkmode;
|
||||
|
||||
// use sync mode
|
||||
vector<string> m_synctime;
|
||||
string m_service;
|
||||
bool m_includedel;
|
||||
|
||||
// config
|
||||
string m_logpath;
|
||||
int m_loglevel;
|
||||
int m_workpoolcnt;
|
||||
vector<int> m_dbpoolcnt;
|
||||
vector<databaseinfo> m_dbinfo;
|
||||
vector<string> m_skipkey;
|
||||
vector<string> m_fhsmount;
|
||||
|
||||
string m_logreport;
|
||||
public:
|
||||
static parameter* getInstance();
|
||||
static void release();
|
||||
|
||||
bool argvtoparam( int argc, char * const argv[] );
|
||||
bool loadconf();
|
||||
|
||||
void print_loginfo();
|
||||
void print_dbinfo();
|
||||
|
||||
|
||||
databaseinfo getdbinfo( int dbinfotype ) { return m_dbinfo[dbinfotype]; }
|
||||
int getdbpoolcnt( int dbinfotype ) { return m_dbpoolcnt[dbinfotype]; }
|
||||
int getskipkeycnt() { return m_skipkey.size(); }
|
||||
string getskipkey(int i) { return m_skipkey[i]; }
|
||||
string getlogpath() { return m_logpath; }
|
||||
string getreportpath() { return m_logreport; }
|
||||
string getsyncpath() { return m_synclistpath; }
|
||||
string gettargetlistpath() { return m_targetlistpath; }
|
||||
int getnetworkmode() { return m_networkmode; }
|
||||
int getloglevel() { return m_loglevel; }
|
||||
int getworkpoolcnt() { return m_workpoolcnt; }
|
||||
string getsyncmode() { return m_mode; }
|
||||
string getsyncstart() { return m_synctime.empty() ? "" : m_synctime[0]; }
|
||||
string getsyncend() { return m_synctime.empty() ? "" : m_synctime[1]; }
|
||||
string getservice() { return m_service; }
|
||||
bool includdel() { return m_includedel; }
|
||||
bool issyncmode() { return (m_mode.compare(MODE_SYNC) == 0); }
|
||||
bool ismovemode() { return (m_mode.compare(MODE_MOVE) == 0); }
|
||||
bool iscopymode() { return (m_mode.compare(MODE_COPY) == 0); }
|
||||
vector<string>& getfhsmount() { return m_fhsmount; }
|
||||
private:
|
||||
parameter();
|
||||
~parameter();
|
||||
|
||||
bool getconfdbinof(Config &conf,int dbinfotype, databaseinfo &data);
|
||||
bool getconfdata(Config &conf, const string& key, string& value, bool bcommon = false, bool returnerr = true);
|
||||
bool getconfdata(Config &conf, const string& key, vector< string >& value, bool bcommon = false, bool returnerr = true);
|
||||
|
||||
void printusage();
|
||||
};
|
||||
#endif // __PARAMETER_H__
|
||||
@@ -0,0 +1,222 @@
|
||||
/***************************************************************************
|
||||
RC Contents Move Tool
|
||||
-----------------------------------------
|
||||
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 __SERVICE_SYNC_H__
|
||||
#define __SERVICE_SYNC_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <cctype>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// -m type
|
||||
#define MODE_SYNC "sync"
|
||||
#define MODE_COPY "copy"
|
||||
#define MODE_MOVE "move"
|
||||
|
||||
// sync file flag
|
||||
#define FLAG_SYNC "SYNC"
|
||||
#define FLAG_NSYNC "NSYNC"
|
||||
#define FLAG_DEL "DEL"
|
||||
#define FLAG_COPY "COPY"
|
||||
#define FLAG_MOVE "MOVE"
|
||||
#define FLAG_RECHK "RECHK"
|
||||
|
||||
// resource_type
|
||||
#define TYPE_FILE "0"
|
||||
#define TYPE_DIR "1"
|
||||
|
||||
#define SPACES " \t\r\n"
|
||||
|
||||
class databaseinfo
|
||||
{
|
||||
public:
|
||||
databaseinfo() {}
|
||||
~databaseinfo() {}
|
||||
public:
|
||||
string m_hostaddr;
|
||||
int m_port;
|
||||
string m_dbname;
|
||||
string m_user;
|
||||
string m_pw;
|
||||
};
|
||||
|
||||
// sync file formate file
|
||||
// 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 : 동기화 필요
|
||||
// - NSYCN: 논리적 동기화 필요
|
||||
// - DEL : 삭제 필요
|
||||
// - COPY : 복사된 파일임
|
||||
// - MOVE : 이동된 파일임
|
||||
// - RECHK: 다시 검증
|
||||
|
||||
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,
|
||||
MAX_FILED
|
||||
};
|
||||
};
|
||||
|
||||
class CURRENT_FIELD
|
||||
{
|
||||
public:
|
||||
enum FIELD
|
||||
{
|
||||
uri = 0, filename_hash, resource_type, get_content_length, get_lastmodified,
|
||||
file_lastmodified, deleted_yn, host_name, creation_date, get_content_type,
|
||||
MAX_FILED
|
||||
};
|
||||
};
|
||||
|
||||
namespace JOB_TYPE
|
||||
{
|
||||
enum JOB_TYPE
|
||||
{
|
||||
UNSET = 0,
|
||||
COPY = 1,
|
||||
MOVE = 2
|
||||
};
|
||||
};
|
||||
|
||||
typedef vector< vector<string> > CSyncData;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Split string function
|
||||
// bUseEmpty값이 true면 delimiter의 갯수에 따라 results.size()의 숫자도 맞추기 위한 옵션
|
||||
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty = false);
|
||||
|
||||
// delim 의 갯수를 리턴한다.
|
||||
int StringCount(string str, string delim);
|
||||
|
||||
// microsecond now time
|
||||
long long longtime_now();
|
||||
|
||||
// string now time
|
||||
string strtime_now();
|
||||
|
||||
// string to time_t
|
||||
time_t str2time_t(string strtime);
|
||||
|
||||
// string to microsecond
|
||||
long long str2longtime(string strtime);
|
||||
|
||||
// 파일의 크기를 가져온다. 파일이 없을 경우 -1 리턴
|
||||
long GetFileSize(const char* path);
|
||||
|
||||
// command 명령어 실행 화면 출력 결과를 string으로 리턴
|
||||
string getCommand(string cmd);
|
||||
|
||||
// trim string right
|
||||
inline string trim_right(const string & s, const string & t = SPACES)
|
||||
{
|
||||
string d (s);
|
||||
string::size_type i (d.find_last_not_of (t));
|
||||
if (i == string::npos)
|
||||
return "";
|
||||
else
|
||||
return d.erase(d.find_last_not_of (t) + 1) ;
|
||||
}
|
||||
|
||||
// trim string left
|
||||
inline string trim_left(const string & s, const string & t = SPACES)
|
||||
{
|
||||
string d (s);
|
||||
return d.erase(0, s.find_first_not_of (t)) ;
|
||||
}
|
||||
|
||||
// trim string left and right
|
||||
inline string trim(const string & s, const string & t = SPACES)
|
||||
{
|
||||
string d (s);
|
||||
return trim_left(trim_right (d, t), t) ;
|
||||
}
|
||||
|
||||
string StringReplace(const string& source, const string search, const string replacement);
|
||||
|
||||
void solusleep(unsigned long usec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#define COUT(level, levelkey, msg) \
|
||||
cout << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
|
||||
|
||||
#define CERR(level, levelkey, msg) \
|
||||
cerr << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
|
||||
|
||||
#else // _DEBUG
|
||||
|
||||
#define COUT(level, levelkey, msg) \
|
||||
if(level < LDBG) \
|
||||
cout << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
|
||||
#define CERR(level, levelkey, msg) \
|
||||
if(level < LDBG) \
|
||||
cerr << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
#define _LOGACOUT(level, msg) \
|
||||
_LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
|
||||
COUT(level, #level,msg);\
|
||||
msg.str("");
|
||||
|
||||
#define LOGACOUT(level, msg) \
|
||||
LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
|
||||
COUT(level, #level, msg);\
|
||||
msg.str("");
|
||||
|
||||
#define _LOGACERR(level, msg) \
|
||||
_LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
|
||||
CERR(level, #level, msg);\
|
||||
msg.str("");
|
||||
|
||||
#define LOGACERR(level, msg) \
|
||||
LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
|
||||
CERR(level, #level, msg);\
|
||||
msg.str("");
|
||||
|
||||
// dummy
|
||||
#define REPORT_SUCCESS(format, ...)
|
||||
#define REPORT_FAIL(format, ...)
|
||||
#define REPORT_WARNING(format, ...)
|
||||
#define REPORT_NOTICE(format, ...)
|
||||
|
||||
#endif // __SERVICE_SYNC_H__
|
||||
Executable
+248
@@ -0,0 +1,248 @@
|
||||
#! /bin/sh
|
||||
|
||||
if [ $# -lt 1 ]
|
||||
then
|
||||
echo "Usage: $0 [FHS Domain name] ([sp_svc_tran_id] [repair])"
|
||||
exit 1
|
||||
fi
|
||||
FHS_HOST=$1
|
||||
REPAIR=$3
|
||||
|
||||
if [ "$2" = "repair" ]; then
|
||||
REPAIR=$2
|
||||
else
|
||||
SP_SVC_TRAN_ID=$2
|
||||
fi
|
||||
|
||||
FHSNAME=$FHS_HOST.data
|
||||
rm -f $FHSNAME 2>&1 > /dev/null
|
||||
|
||||
PSQL="/user/service/bin/psql"
|
||||
RCDB=`grep "^RCDB_IP" /user/service/etc/rcts.conf | grep -v "\_SLAVE" | cut -d = -f 2`
|
||||
PORT=6543
|
||||
RCDBNAME="localdb"
|
||||
RCDBUSER="syshost"
|
||||
|
||||
PSQLRUN="$PSQL -h $RCDB -p $PORT -U $RCDBUSER -A -t -c"
|
||||
|
||||
META="t_dav_resource"
|
||||
GET_URICOMM=uri
|
||||
## check RCDB Type
|
||||
SQL="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname = 'public' AND tablename = '$META'"
|
||||
OLDRCDB=`$PSQLRUN "$SQL" $RCDBNAME`
|
||||
echo "#### Meta Type : $OLDRCDB"
|
||||
|
||||
## Get Service
|
||||
SQL="SELECT sp_svc_tran_id, uri_ignore_case, replication_count FROM t_sms_sp_svc_product"
|
||||
if [ -n "$SP_SVC_TRAN_ID" ]; then
|
||||
SQL="SELECT sp_svc_tran_id, uri_ignore_case, replication_count FROM t_sms_sp_svc_product WHERE sp_svc_tran_id = $SP_SVC_TRAN_ID"
|
||||
fi
|
||||
SVC_LIST=`$PSQLRUN "$SQL" $RCDBNAME`
|
||||
for v in $SVC_LIST
|
||||
do
|
||||
tran_id=`echo $v | cut -d '|' -f 1`
|
||||
uri_ignore_case=`echo $v | cut -d '|' -f 2`
|
||||
replication_count=`echo $v | cut -d '|' -f 3`
|
||||
echo -n " ##### $tran_id, $uri_ignore_case "
|
||||
if [ "$OLDRCDB" = "0" ]; then
|
||||
META="t_meta_$tran_id"
|
||||
GET_URICOMM="display_name"
|
||||
fi
|
||||
echo -n "$META "
|
||||
## Get Data
|
||||
if [ "$REPAIR" = "repair" ]; then
|
||||
### uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|is_cache|host_name|creation_date|get_content_type|src_uri|slave tran_id|uri_ignore_case|replication_count
|
||||
SQL="SELECT uri,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,is_cache,host_name,creation_date,get_content_type,'',sp_svc_tran_id, '$uri_ignore_case', '$replication_count' FROM $META"
|
||||
else
|
||||
### 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
|
||||
SQL="SELECT 'MOVE',$GET_URICOMM,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,host_name,creation_date,get_content_type,'',sp_svc_tran_id, '$uri_ignore_case' FROM $META"
|
||||
fi
|
||||
|
||||
SQLGET="$SQL WHERE uri like '/$tran_id/%' AND deleted_yn = 'N' AND host_name = '$FHS_HOST'"
|
||||
#echo "######### $SQLGET"
|
||||
$PSQLRUN "$SQLGET" $RCDBNAME >> $FHSNAME
|
||||
|
||||
echo "...[OK]"
|
||||
done
|
||||
|
||||
if [ "$REPAIR" = "repair" ]; then
|
||||
echo "... MODE : repair "
|
||||
while read line
|
||||
do
|
||||
same=();
|
||||
same_host=();
|
||||
same_uri_attr_cache=();
|
||||
same_uri_cache_n=();
|
||||
same_uri_cache_r=();
|
||||
same_attr_cache=();
|
||||
attr_cache_y=();
|
||||
other_uri_cache_n=();
|
||||
other_uri_cache_r=();
|
||||
check=();
|
||||
|
||||
#echo $line
|
||||
uri=`echo $line | cut -d '|' -f 1`
|
||||
filename_hash=`echo $line | cut -d '|' -f 2`
|
||||
filename_hash_in=`echo $filename_hash | sed -e 's|/stg/node0/||g' | sed -e 's|/stg/node1/||g' | sed -e 's|/stg/node2/||g' | sed -e 's|/user2/dav_storage/||g'`
|
||||
filename_hashs="'/stg/node0/$filename_hash_in','/stg/node1/$filename_hash_in','/stg/node2/$filename_hash_in','/user2/dav_storage/$filename_hash_in','/stg/node0/cache/$filename_hash_in','/stg/node1/cache/$filename_hash_in','/stg/node2/cache/$filename_hash_in','/user2/dav_storage/cache/$filename_hash_in'"
|
||||
resource_type=`echo $line | cut -d '|' -f 3`
|
||||
get_content_length=`echo $line | cut -d '|' -f 4`
|
||||
is_cache=`echo $line | cut -d '|' -f 7`
|
||||
host_name=`echo $line | cut -d '|' -f 8`
|
||||
tran_id=`echo $line | cut -d '|' -f 12`
|
||||
replication_count=`echo $line | cut -d '|' -f 14`
|
||||
|
||||
## dir skip
|
||||
if [ $resource_type -eq 1 ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$OLDRCDB" = "0" ]; then
|
||||
META="t_meta_$tran_id"
|
||||
fi
|
||||
|
||||
|
||||
#echo "....... $tran_id, $replication_count, $META, $host_name, $uri, $filename_hash($filename_hash_in), $resource_type, $is_cache"
|
||||
|
||||
## cache file delete
|
||||
if [ "$is_cache" = "Y" ]; then
|
||||
SQLSET="UPDATE $META SET deleted_yn = 'Y' "
|
||||
SQL="SQLSET WHERE filename_hash = '$filename_hash' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'Y' AND host_name = '$host_name' ;"
|
||||
|
||||
$PSQLRUN "$SQL" $RCDBNAME
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ".......... $uri, $filename_hash [DEL]"
|
||||
else
|
||||
echo ".......... $uri, $filename_hash [DEL] FAILED"
|
||||
break
|
||||
fi
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
SQL="SELECT uri,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,is_cache,host_name FROM $META"
|
||||
|
||||
SQLGET="$SQL WHERE filename_hash in ($filename_hashs) AND deleted_yn = 'N' AND resource_type = 0 AND get_content_length = $get_content_length ;"
|
||||
#echo "......... $SQLGET"
|
||||
|
||||
data=`$PSQLRUN "$SQLGET" $RCDBNAME`
|
||||
for v in $data
|
||||
do
|
||||
#echo ".......... $v"
|
||||
if [ `echo $v | grep "$uri" | grep "$host_name" | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same]"
|
||||
same[${#same[@]}]=$v
|
||||
elif [ `echo $v | grep -c "$host_name" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_host]"
|
||||
same_host[${#same_host[@]}]=$v
|
||||
elif [ `echo $v | grep "$uri" | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_uri_attr_cache]"
|
||||
same_uri_attr_cache[${#same_uri_attr_cache[@]}]=$v
|
||||
elif [ `echo $v | grep "$uri" | grep -c "|N|N|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_uri_cache_n]"
|
||||
same_uri_cache_n[${#same_uri_cache_n[@]}]=$v
|
||||
elif [ `echo $v | grep "$uri" | grep -c "|N|R|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_uri_cache_r]"
|
||||
same_uri_cache_r[${#same_uri_cache_r[@]}]=$v
|
||||
elif [ `echo $v | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_attr_cache]"
|
||||
same_attr_cache[${#same_attr_cache[@]}]=$v
|
||||
elif [ `echo $v | grep -c "|N|Y|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [same_attr_cache]"
|
||||
attr_cache_y[${#attr_cache_y[@]}]=$v
|
||||
elif [ `echo $v | grep -c "|N|N|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [outher_uri_cache_n]"
|
||||
other_uri_cache_n[${#other_uri_cache_n[@]}]=$v
|
||||
elif [ `echo $v | grep -c "|N|R|" ` -gt 0 ] ; then
|
||||
#echo "............. $v [other_uri_cache_r]"
|
||||
other_uri_cache_r[${#other_uri_cache_r[@]}]=$v
|
||||
else
|
||||
echo "............. [$line] => [$v] [check]"
|
||||
check[${#check[@]}]=$v
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
#echo -n "............"
|
||||
##echo -n " $line"
|
||||
#echo -n " [same : ${#same[@]}, same_host :${#same_host[@]}"
|
||||
#echo -n ", same_uri_attr_cache: ${#same_uri_attr_cache[@]}"
|
||||
#echo -n ", same_uri_cache_n: ${#same_uri_cache_n[@]}"
|
||||
#echo -n ", same_uri_cache_r: ${#same_uri_cache_r[@]}"
|
||||
#echo -n ", same_attr_cache : ${#same_attr_cache[@]}"
|
||||
#echo -n ", attr_cache_y: ${#attr_cache_y[@]}"
|
||||
#echo -n ", other_uri_cache_n: ${#other_uri_cache_n[@]}"
|
||||
#echo -n ", other_uri_cache_r: ${#other_uri_cache_r[@]}"
|
||||
#echo ", check : ${#check[@]}]"
|
||||
|
||||
if [ ${#same[@]} -eq 0 ]; then
|
||||
echo ".......... $uri, $filename_hash, $host_name [Not Found]"
|
||||
continue
|
||||
fi
|
||||
|
||||
filename_hash2=""
|
||||
host_name2=""
|
||||
SQLSET=""
|
||||
SQL2=""
|
||||
|
||||
if [ ${#same_attr_cache[@]} -gt 0 ]; then
|
||||
echo "########### same_attr_cache: ${#same_attr_cache[@]} : ${same_attr_cache[0]}"
|
||||
filename_hash2=`echo ${same_attr_cache[0]} | cut -d '|' -f 2`
|
||||
host_name2=`echo ${same_attr_cache[0]} | cut -d '|' -f 8`
|
||||
|
||||
SQLSET="UPDATE $META SET filename_hash = '$filename_hash2', host_name = '$host_name2'"
|
||||
SQL2="$SQLSET WHERE filename_hash = '$filename_hash' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = '$is_cache' AND host_name = '$host_name' ;"
|
||||
elif [ ${#attr_cache_y[@]} -gt 0 ] ; then
|
||||
echo "########### attr_cache_y: ${#attr_cache_y[@]} : ${attr_cache_y[0]}"
|
||||
filename_hash2=`echo ${attr_cache_y[0]} | cut -d '|' -f 2`
|
||||
host_name2=`echo ${attr_cache_y[0]} | cut -d '|' -f 8`
|
||||
|
||||
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
|
||||
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'Y' AND host_name = '$host_name2' ;"
|
||||
else
|
||||
case "$is_cache" in
|
||||
"N")
|
||||
#echo ".......... $line ['N' case]"
|
||||
if [ ${#same_uri_cache_r[@]} -gt $replication_count ]; then
|
||||
#echo "########### same_uri_cache_r: ${#same_uri_cache_r[@]} : ${same_uri_cache_r[0]}"
|
||||
filename_hash2=`echo ${same_uri_cache_r[0]} | cut -d '|' -f 2`
|
||||
host_name2=`echo ${same_uri_cache_r[0]} | cut -d '|' -f 8`
|
||||
|
||||
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
|
||||
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'R' AND host_name = '$host_name2' ;"
|
||||
elif [ ${#other_uri_cache_r[@]} -gt $replication_count ] ; then
|
||||
#echo "########### other_uri_cache_r: ${#other_uri_cache_r[@]} : ${other_uri_cache_r[0]}"
|
||||
filename_hash2=`echo ${other_uri_cache_r[0]} | cut -d '|' -f 2`
|
||||
host_name2=`echo ${other_uri_cache_r[0]} | cut -d '|' -f 8`
|
||||
|
||||
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
|
||||
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'R' AND host_name = '$host_name2' ;"
|
||||
fi
|
||||
;;
|
||||
#"R")
|
||||
# echo ".......... $line ['R' case]"
|
||||
#;;
|
||||
*)
|
||||
echo "$line [Unknown error]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
if [ -n "$SQL2" ]; then
|
||||
#echo "............ repair SQL : [$SQL2] "
|
||||
$PSQLRUN "$SQL2" $RCDBNAME
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ".......... $uri, $filename_hash [OK]"
|
||||
else
|
||||
echo ".......... $uri, $filename_hash [UPDATE] FAILED"
|
||||
fi
|
||||
else
|
||||
echo ".......... $uri, $filename_hash [rc_cmove]"
|
||||
fi
|
||||
|
||||
done < $FHSNAME
|
||||
rm -f $FHSNAME
|
||||
echo "... MODE : repair [Done]"
|
||||
fi
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
Synchronization
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 __SYNCHRONIZATION_H__
|
||||
#define __SYNCHRONIZATION_H__
|
||||
|
||||
class DataBase;
|
||||
class CSynchronization
|
||||
{
|
||||
public:
|
||||
CSynchronization(JOB_TYPE::JOB_TYPE type, vector<string>& syncdata);
|
||||
~CSynchronization();
|
||||
|
||||
// 실행
|
||||
int Execute();
|
||||
|
||||
|
||||
void SetTragetHost(vector<string> &src);
|
||||
|
||||
inline void SetEnable(const char* szOn) { m_enable = szOn; }
|
||||
inline void SetNetworkMode(int mode) { m_networkmode = mode; }
|
||||
inline void SetFHSMount(vector<string> &mount) { m_fhsmount = mount; }
|
||||
|
||||
protected:
|
||||
// TOP FHS 정보를 가져온다. (가져온후 random으로 1개를 추출하여 return 함)
|
||||
bool GetTargetFHS(string & targethost);
|
||||
|
||||
// copy(move)에 source 정보 찾기
|
||||
bool GetSource(string & srchost, string & srchash);
|
||||
|
||||
// 동일한 파일 가지고 있는 host 추출
|
||||
bool GetHostHasFile(string & srchosts);
|
||||
|
||||
// ftsd를 이용한 파일전송
|
||||
bool ReqFileTrans(string & strsrc, vector<string>& vecdest);
|
||||
|
||||
// kind of sync
|
||||
int Deleted();
|
||||
int Syned();
|
||||
int NSyned();
|
||||
int Copy();
|
||||
int Move();
|
||||
int MoveTypeCopy();
|
||||
int MoveTypeMove();
|
||||
int Rechk();
|
||||
|
||||
// change value
|
||||
string ChgFilenamehash();
|
||||
string MakeFilenameorg();
|
||||
|
||||
// Database
|
||||
DataBase* GetDB(string & tblname, bool & usedisplay);
|
||||
void FreeDB(DataBase *db, bool success = true);
|
||||
|
||||
private:
|
||||
string m_enable;
|
||||
int m_networkmode;
|
||||
vector<string> m_fhsmount;
|
||||
|
||||
vector<string> m_vecTargetFHS; // target TOP FHS
|
||||
|
||||
JOB_TYPE::JOB_TYPE m_type;
|
||||
vector<string> m_syncdata;
|
||||
|
||||
bool m_exit;
|
||||
};
|
||||
|
||||
#endif // __SYNCHRONIZATION_H__
|
||||
@@ -0,0 +1,891 @@
|
||||
/***************************************************************************
|
||||
Validation
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 "rc_cmove.h"
|
||||
#include "parameter.h"
|
||||
#include "validation.h"
|
||||
#include "Database.h"
|
||||
#include "dbconnpool.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ReportLog.h"
|
||||
|
||||
#define RECHK_TIMEOUT (24*60*60 * 1000000LL) // 1 day
|
||||
|
||||
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(JOB_TYPE::JOB_TYPE type, vector<string> & input)
|
||||
: m_type(type), m_syncdata(input), m_first(true)
|
||||
{
|
||||
}
|
||||
|
||||
CValidation::~CValidation()
|
||||
{
|
||||
}
|
||||
|
||||
DataBase* CValidation::GetDB(string & tblname, bool & usedisplay)
|
||||
{
|
||||
ostringstream msg;
|
||||
string s = m_syncdata[SYNCFILE_FIELD::slave_tran_id];
|
||||
|
||||
if (s.empty())
|
||||
{
|
||||
msg << "Service information empty.";
|
||||
LOGACERR(LERR, msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DataBase* db = masterdbpool::getInstance()->GetConnFromPool();
|
||||
tblname = masterdbpool::getInstance()->GetMetaTableName(s.c_str());
|
||||
usedisplay = masterdbpool::getInstance()->UseDisplayname();
|
||||
|
||||
if (db == NULL)
|
||||
{
|
||||
msg << "DB POOL doesn't assign a database..";
|
||||
LOGACERR(LERR, msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return db;
|
||||
}
|
||||
void CValidation::FreeDB(DataBase *db, bool success/* = true*/)
|
||||
{
|
||||
if (db)
|
||||
{
|
||||
masterdbpool::getInstance()->ReleaseConnToPool(db, success);
|
||||
db = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> CValidation::Current2Sync(string sflag, vector<string>& curr)
|
||||
{
|
||||
vector<string> r(SYNCFILE_FIELD::MAX_FILED);
|
||||
|
||||
r[SYNCFILE_FIELD::flag] = sflag;
|
||||
r[SYNCFILE_FIELD::uri] = curr[CURRENT_FIELD::uri];
|
||||
r[SYNCFILE_FIELD::filename_hash] = curr[CURRENT_FIELD::filename_hash];
|
||||
r[SYNCFILE_FIELD::resource_type] = curr[CURRENT_FIELD::resource_type];
|
||||
r[SYNCFILE_FIELD::file_lastmodified] = curr[CURRENT_FIELD::file_lastmodified];
|
||||
r[SYNCFILE_FIELD::deleted_yn] = curr[CURRENT_FIELD::deleted_yn];
|
||||
r[SYNCFILE_FIELD::host_name] = curr[CURRENT_FIELD::host_name];
|
||||
r[SYNCFILE_FIELD::creation_date] = curr[CURRENT_FIELD::creation_date];
|
||||
r[SYNCFILE_FIELD::get_content_length] = curr[CURRENT_FIELD::get_content_length];
|
||||
r[SYNCFILE_FIELD::get_content_type] = curr[CURRENT_FIELD::get_content_type];
|
||||
|
||||
r[SYNCFILE_FIELD::src_uri] = m_syncdata[SYNCFILE_FIELD::src_uri];
|
||||
r[SYNCFILE_FIELD::slave_tran_id] = m_syncdata[SYNCFILE_FIELD::slave_tran_id];
|
||||
r[SYNCFILE_FIELD::uri_ignore_case] = m_syncdata[SYNCFILE_FIELD::uri_ignore_case];
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
string CValidation::GetFullFilenamehash()
|
||||
{
|
||||
string r;
|
||||
ostringstream msg;
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
|
||||
{
|
||||
msg << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "] isn't file.";
|
||||
LOGACOUT(LDBG, msg);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (m_type == JOB_TYPE::COPY)
|
||||
{
|
||||
//m_syncdata[SYNCFILE_FIELD::filename_hash]
|
||||
unsigned found = m_syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
|
||||
string hash = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] +
|
||||
m_syncdata[SYNCFILE_FIELD::filename_hash].substr(found);
|
||||
|
||||
if (m_fhsmount.size())
|
||||
{
|
||||
for (vector<string>::size_type i = 0; i < m_fhsmount.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
r += ",";
|
||||
r += m_fhsmount[i] + hash;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "FHS mount empty.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LWAR, msg);
|
||||
|
||||
r = m_syncdata[SYNCFILE_FIELD::filename_hash];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = m_syncdata[SYNCFILE_FIELD::filename_hash];
|
||||
}
|
||||
|
||||
r = StringReplace(r, "{", "\\{");
|
||||
r = StringReplace(r, "}", "\\}");
|
||||
|
||||
r = "{" + r + "}";
|
||||
|
||||
msg << "Useing SQL filename_hash : " << m_syncdata[SYNCFILE_FIELD::filename_hash]
|
||||
<< " => " << r;
|
||||
|
||||
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CValidation::GetCurrent(DataBase *db, string& tblname, bool useDisyplay /* = true */)
|
||||
{
|
||||
ostringstream sql,msg;
|
||||
|
||||
int index = 1;
|
||||
|
||||
sql << "SELECT ";
|
||||
if (useDisyplay)
|
||||
sql << "display_name, ";
|
||||
else
|
||||
sql << "uri, ";
|
||||
sql << "filename_hash, resource_type, get_content_length, get_lastmodified, ";
|
||||
sql << "file_lastmodified, deleted_yn, host_name, creation_date, get_content_type ";
|
||||
|
||||
sql << "FROM " << tblname << " ";
|
||||
|
||||
sql << "WHERE ";
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
|
||||
{
|
||||
index = 1;
|
||||
sql << "filename_hash = ANY ($1) ";
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 2;
|
||||
sql << "depth = $1 ";
|
||||
sql << "AND ";
|
||||
|
||||
if (useDisyplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
|
||||
sql << "uri = lower($2) ";
|
||||
else
|
||||
sql << "uri = $2 ";
|
||||
}
|
||||
|
||||
if (m_type == JOB_TYPE::MOVE)
|
||||
{
|
||||
sql << "AND ";
|
||||
sql << "host_name = $" << ++index << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
sql << "AND ";
|
||||
sql << "is_cache = 'N' ";
|
||||
}
|
||||
|
||||
sql << "AND ";
|
||||
sql << "deleted_yn = 'N' ";
|
||||
|
||||
|
||||
ostringstream t;
|
||||
string struri = m_syncdata[SYNCFILE_FIELD::uri];
|
||||
string strdepth;
|
||||
string strhash = GetFullFilenamehash();
|
||||
|
||||
// depth 값 구하기. path : /tran_id/filename ( tran_id 제거된 count )
|
||||
int nDEPTH = StringCount(struri, "/") - 1;
|
||||
|
||||
t << nDEPTH;
|
||||
strdepth = t.str(); t.str("");
|
||||
|
||||
const char *paramValues[5];
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
|
||||
{
|
||||
index = 1;
|
||||
paramValues[0] = strhash.c_str();
|
||||
msg << " RCDB GetCurrent value : " << paramValues[0] << ",";
|
||||
}
|
||||
else
|
||||
{
|
||||
index = 2;
|
||||
paramValues[0] = strdepth.c_str();
|
||||
paramValues[1] = struri.c_str();
|
||||
msg << paramValues[0] << "," << paramValues[1] << ",";
|
||||
}
|
||||
|
||||
if (m_type == JOB_TYPE::MOVE)
|
||||
{
|
||||
paramValues[index++] = m_syncdata[SYNCFILE_FIELD::host_name].c_str();
|
||||
msg << paramValues[index - 1] << ",INDEX (" << index << ")";
|
||||
}
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
msg << "SQL - " << sql.str();
|
||||
LOGACOUT(LDBG, msg);
|
||||
// Query 실행
|
||||
db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);
|
||||
|
||||
// Query 결과를 가져온다.
|
||||
int nResult = db->PgResult(DataBase::NOT_CLEAR);
|
||||
if (nResult < 0)
|
||||
{
|
||||
msg << "RCDB GetCurrent failed : [" << db->GetErrorMessage() << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < db->GetNoTuples(); ++i)
|
||||
{
|
||||
vector<string> vectcurr(CURRENT_FIELD::MAX_FILED);
|
||||
|
||||
vectcurr[CURRENT_FIELD::uri] = db->GetValue(i, CURRENT_FIELD::uri);
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] == "0")
|
||||
vectcurr[CURRENT_FIELD::filename_hash] = db->GetValue(i, CURRENT_FIELD::filename_hash);
|
||||
|
||||
vectcurr[CURRENT_FIELD::host_name] = db->GetValue(i, CURRENT_FIELD::host_name);
|
||||
vectcurr[CURRENT_FIELD::resource_type] = db->GetValue(i, CURRENT_FIELD::resource_type);
|
||||
vectcurr[CURRENT_FIELD::creation_date] = db->GetValue(i, CURRENT_FIELD::creation_date);
|
||||
vectcurr[CURRENT_FIELD::get_content_length] = db->GetValue(i, CURRENT_FIELD::get_content_length);
|
||||
vectcurr[CURRENT_FIELD::get_content_type] = db->GetValue(i, CURRENT_FIELD::get_content_type);
|
||||
vectcurr[CURRENT_FIELD::get_lastmodified] = db->GetValue(i, CURRENT_FIELD::get_lastmodified);
|
||||
vectcurr[CURRENT_FIELD::deleted_yn] = db->GetValue(i, CURRENT_FIELD::deleted_yn);
|
||||
vectcurr[CURRENT_FIELD::file_lastmodified] = db->GetValue(i, CURRENT_FIELD::file_lastmodified);
|
||||
|
||||
m_current.insert(CCurretMap::value_type(vectcurr[CURRENT_FIELD::uri], vectcurr));
|
||||
}
|
||||
|
||||
db->PgClear();
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<string> CValidation::MakeFind()
|
||||
{
|
||||
vector<string> r;
|
||||
|
||||
string strtran = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
|
||||
|
||||
if (m_first && m_type == JOB_TYPE::COPY)
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY
|
||||
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
|
||||
{
|
||||
// 마스터 망에서 파일 수정일(get_lastmodified)이 해당 파일보다 작은 것이 없을 경우 src_uri 보내지 않음
|
||||
if (m_syncdata[SYNCFILE_FIELD::src_uri].size())
|
||||
{
|
||||
string srcuri = strtran + m_syncdata[SYNCFILE_FIELD::src_uri];
|
||||
r.push_back(srcuri);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string input = m_syncdata[SYNCFILE_FIELD::uri];
|
||||
r.push_back(input);
|
||||
return r;
|
||||
}
|
||||
|
||||
int CValidation::IsAllow()
|
||||
{
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_RECHK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int r = -1;
|
||||
switch (m_type)
|
||||
{
|
||||
case JOB_TYPE::COPY:
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC
|
||||
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC
|
||||
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL
|
||||
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY
|
||||
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
|
||||
r = 0;
|
||||
}
|
||||
break;
|
||||
case JOB_TYPE::MOVE:
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
|
||||
r = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
r = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CValidation::FindZero(string & input, CSyncData & outSync)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND ZERO";
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
string synctranid = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
|
||||
string src = synctranid + m_syncdata[SYNCFILE_FIELD::src_uri];
|
||||
|
||||
// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
|
||||
if (m_type == JOB_TYPE::COPY && m_first && m_current.size())
|
||||
{
|
||||
// RECHK
|
||||
for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
|
||||
{
|
||||
vector<string> newsync = Current2Sync(FLAG_RECHK, it->second);
|
||||
|
||||
if (input == newsync[SYNCFILE_FIELD::uri])
|
||||
continue;
|
||||
|
||||
// input : destination
|
||||
if (src == newsync[SYNCFILE_FIELD::uri])
|
||||
continue;
|
||||
|
||||
// input : source
|
||||
if (src == input)
|
||||
continue;
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::get_content_length] == newsync[SYNCFILE_FIELD::get_content_length])
|
||||
{
|
||||
string newsrc = newsync[SYNCFILE_FIELD::uri];
|
||||
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
|
||||
}
|
||||
}
|
||||
|
||||
//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);
|
||||
|
||||
//if (longtime_now() - d > RECHK_TIMEOUT)
|
||||
{
|
||||
outSync.push_back(newsync);
|
||||
|
||||
msg << "Set RECHK....[" << newsync[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
|
||||
{
|
||||
msg << "Does not process a request to delete a file because it does not exist currently. [" << input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
|
||||
{
|
||||
// 해당 파일과 동일한 파일 존재 확인
|
||||
if (m_first)
|
||||
{
|
||||
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
|
||||
{
|
||||
if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
|
||||
{
|
||||
if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
|
||||
{
|
||||
string newsrc = (*it)[SYNCFILE_FIELD::uri];
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
|
||||
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
|
||||
{
|
||||
msg << "Because the file does not exist, "
|
||||
<< "change the physical synchronization from the logical synchronization. ["
|
||||
<< input << "]";
|
||||
|
||||
LOGACOUT(LINF, msg);
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
}
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_DIR)
|
||||
{
|
||||
msg << "Create DIR. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
m_syncdata[SYNCFILE_FIELD::host_name] = "";
|
||||
}
|
||||
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY )
|
||||
{
|
||||
if (input == src)
|
||||
{
|
||||
vector<string> newsync = m_syncdata;
|
||||
newsync[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
newsync[SYNCFILE_FIELD::uri] = src;
|
||||
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
|
||||
{
|
||||
if (m_type == JOB_TYPE::MOVE)
|
||||
{
|
||||
msg << "Because the file does not exist, can not be transferred. [" << input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (input == src)
|
||||
{
|
||||
// Nothing
|
||||
msg << "The source file does not exist, Nothing... [" << input << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
|
||||
bool findsrc = false;
|
||||
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
|
||||
{
|
||||
if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
|
||||
{
|
||||
if ((*it)[SYNCFILE_FIELD::uri] == src)
|
||||
{
|
||||
findsrc = true;
|
||||
outSync.erase(it);
|
||||
break;
|
||||
}
|
||||
|
||||
// 해당 소스와 동일한 uri 존재하지 하지 않지만 동일한 파일로 다른 uri 존재할 수 있으므로
|
||||
// 해당 파일을 소스 파일로 하는 copy 본 생성함
|
||||
// 소스로 선정된 파일은 RECHK 옵션에 의해서 재처리됨
|
||||
if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
|
||||
{
|
||||
findsrc = true;
|
||||
string newsrc = (*it)[SYNCFILE_FIELD::uri];
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
|
||||
m_syncdata[SYNCFILE_FIELD::host_name] = (*it)[SYNCFILE_FIELD::host_name];
|
||||
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 소스 존재 하지 않을 경우 SYNC로 변경
|
||||
if (findsrc == false)
|
||||
{
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
}
|
||||
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
|
||||
msg << input;
|
||||
msg << "]";
|
||||
|
||||
LOGACERR(LERR, msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CValidation::FindOne(vector<string> f, CSyncData & outSync)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
string input = f[CURRENT_FIELD::uri];
|
||||
string src = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] + m_syncdata[SYNCFILE_FIELD::src_uri];
|
||||
|
||||
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND IT";
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
|
||||
if (m_type == JOB_TYPE::COPY && m_first && m_current.size() > 1)
|
||||
{
|
||||
// RECHK
|
||||
for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
|
||||
{
|
||||
vector<string> newsync = Current2Sync(FLAG_RECHK, it->second);
|
||||
if (input == newsync[SYNCFILE_FIELD::uri])
|
||||
continue;
|
||||
|
||||
// input : destination
|
||||
if (src == newsync[SYNCFILE_FIELD::uri])
|
||||
continue;
|
||||
|
||||
// input : source
|
||||
if (src == input)
|
||||
continue;
|
||||
|
||||
//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);
|
||||
|
||||
//if (longtime_now() - d > RECHK_TIMEOUT)
|
||||
{
|
||||
outSync.push_back(newsync);
|
||||
|
||||
msg << "Set RECHK(1)....[" << newsync[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool in2sync = false;
|
||||
// check
|
||||
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
|
||||
{
|
||||
in2sync = true;
|
||||
if (m_first && m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
|
||||
{
|
||||
msg << "uri same but size different. change flag(RECHK).[" << input << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_RECHK;
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
|
||||
{
|
||||
in2sync = true;
|
||||
|
||||
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
msg << "uri same but size different. new syncdata(DEL) create.[" << input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_DEL, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
msg << "uri same but file_lastmodified different. new syncdata(NSYNC) create.[" << input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_NSYNC, f);
|
||||
newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
in2sync = false;
|
||||
msg << "Information all same. not synchronized.[" << input << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
|
||||
{
|
||||
in2sync = true;
|
||||
if (f[CURRENT_FIELD::resource_type] == TYPE_DIR)
|
||||
m_syncdata[SYNCFILE_FIELD::host_name] = f[CURRENT_FIELD::host_name];
|
||||
}
|
||||
|
||||
if (f[CURRENT_FIELD::resource_type] == TYPE_FILE)
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
msg << "uri same but size(or file_lastmodified) different. new syncdata(DEL) create.["
|
||||
<< input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_DEL, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "Change flag NSYNC to SYNC. [" << input << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY)
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
msg << "uri same but size different. new syncdata(DEL) create.["
|
||||
<< input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_DEL, f);
|
||||
outSync.push_back(newsync);
|
||||
|
||||
if (input == src)
|
||||
{
|
||||
msg << "uri same but size different. new syncdata(SYNC) create.["
|
||||
<< input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
newsync = Current2Sync(FLAG_SYNC, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
else
|
||||
in2sync = true;
|
||||
}
|
||||
else
|
||||
in2sync = true;
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
if (input != src)
|
||||
{
|
||||
vector<string> newsync = Current2Sync(FLAG_NSYNC, f);
|
||||
newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
|
||||
{
|
||||
if (m_type == JOB_TYPE::MOVE)
|
||||
{
|
||||
in2sync = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
|
||||
{
|
||||
if (m_first)
|
||||
{
|
||||
msg << "uri same but size different. new syncdata(DEL) create.["
|
||||
<< input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_DEL, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
|
||||
if (input != src)
|
||||
{
|
||||
msg << "uri same but size different. new syncdata(SYNC) create.["
|
||||
<< input << "]";
|
||||
LOGACOUT(LINF, msg);
|
||||
vector<string> newsync = Current2Sync(FLAG_SYNC, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (input == src)
|
||||
{
|
||||
vector<string> newsync = Current2Sync(FLAG_RECHK, f);
|
||||
outSync.push_back(newsync);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
|
||||
{
|
||||
if ((*it)[SYNCFILE_FIELD::uri] == src )
|
||||
{
|
||||
// 소스 존재하고 복사된 파일도 존재하면 소스 삭제 처리
|
||||
(*it)[SYNCFILE_FIELD::flag] = FLAG_DEL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
|
||||
msg << input;
|
||||
msg << "]";
|
||||
|
||||
LOGACERR(LERR, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// input to sync data
|
||||
if (in2sync)
|
||||
{
|
||||
outSync.push_back(m_syncdata);
|
||||
}
|
||||
}
|
||||
|
||||
void CValidation::FindOver(pair<CCurretMap::iterator, CCurretMap::iterator> &f, CSyncData & outSync)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
//f.first
|
||||
CCurretMap::iterator vf = f.first;
|
||||
|
||||
string input = (*vf).second[CURRENT_FIELD::uri];
|
||||
|
||||
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> DUPLICATE";
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
CReportLog rlog;
|
||||
|
||||
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
|
||||
{
|
||||
rlog.Write("NOT", "[%s] [The duplicate files.[uri :%s]]", PROG_NAME, input.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CValidation::CompareData(DataBase *db, string& tblname,
|
||||
vector<string> & vecFind, CSyncData & outSync)
|
||||
{
|
||||
bool r = true;
|
||||
ostringstream msg;
|
||||
|
||||
msg << "FIND vector Size : " << vecFind.size();
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
while (vecFind.size())
|
||||
{
|
||||
string input = vecFind.front();
|
||||
msg << "FIND input : " << input;
|
||||
LOGACOUT(LDEV1, msg);
|
||||
|
||||
pair<CCurretMap::iterator, CCurretMap::iterator> f = m_current.equal_range(input);
|
||||
CCurretMap::const_iterator ff = f.first;
|
||||
|
||||
if (f.first == m_current.end())
|
||||
{
|
||||
// find zero
|
||||
FindZero(input, outSync);
|
||||
}
|
||||
else if (++ff == f.second)
|
||||
{
|
||||
// find one
|
||||
CCurretMap::iterator v = f.first;
|
||||
FindOne((*v).second, outSync);
|
||||
}
|
||||
else
|
||||
{
|
||||
// find one over
|
||||
FindOver(f, outSync);
|
||||
return false;
|
||||
}
|
||||
|
||||
vecFind.erase(vecFind.begin());
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int CValidation::CheckData(bool first, CSyncData & outSync)
|
||||
{
|
||||
DataBase* db = NULL;
|
||||
string tblname;
|
||||
bool usedisp = true;
|
||||
ostringstream msg;
|
||||
|
||||
m_first = first;
|
||||
|
||||
// check allow
|
||||
switch (IsAllow())
|
||||
{
|
||||
case 0: // Allow
|
||||
msg << "ALLOW Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LDEV2, msg);
|
||||
break;
|
||||
case 1: // SKIP
|
||||
msg << "SIKP Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LDBG, msg);
|
||||
|
||||
outSync.push_back(m_syncdata);
|
||||
return 0;
|
||||
break;
|
||||
default: // Deny
|
||||
msg << "DENY Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LERR, msg);
|
||||
return -10;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get DB
|
||||
db = GetDB(tblname, usedisp);
|
||||
if (db == NULL)
|
||||
return -1;
|
||||
|
||||
int r = 0;
|
||||
do
|
||||
{
|
||||
// Get Current
|
||||
if (GetCurrent(db, tblname, usedisp) == false)
|
||||
{
|
||||
r = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
// Make Find URI
|
||||
vector<string> vecfind = MakeFind();
|
||||
if (vecfind.empty())
|
||||
{
|
||||
r = -3;
|
||||
msg << "Not Found 'FIND URI'.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LERR, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
// compare
|
||||
if (CompareData(db, tblname, vecfind, outSync) == false)
|
||||
{
|
||||
r = -4;
|
||||
break;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
|
||||
// Free DB
|
||||
FreeDB(db, (r != -2));
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
Validation
|
||||
-----------------------------------------
|
||||
begin : 2012/05/14
|
||||
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 __VALIDATION_H__
|
||||
#define __VALIDATION_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
# if __GNUC__ >= 3
|
||||
# include <ext/hash_map>
|
||||
using namespace __gnu_cxx;
|
||||
# else
|
||||
# include <hash_map>
|
||||
# endif
|
||||
|
||||
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 DataBase;
|
||||
class CValidation
|
||||
{
|
||||
public:
|
||||
CValidation(JOB_TYPE::JOB_TYPE type, vector<string> & input);
|
||||
~CValidation();
|
||||
|
||||
int CheckData(bool first, CSyncData & outSync);
|
||||
|
||||
void SetFHSMount(vector<string>& fhs) { m_fhsmount = fhs; }
|
||||
|
||||
private:
|
||||
bool CompareData(DataBase *db, string& tblname,
|
||||
vector<string> & vecFind, CSyncData & outSync);
|
||||
|
||||
int IsAllow();
|
||||
|
||||
vector<string> MakeFind();
|
||||
|
||||
void FindZero(string & inuri, CSyncData & outSync);
|
||||
void FindOne(vector<string> f, CSyncData & outSync);
|
||||
void FindOver(pair<CCurretMap::iterator, CCurretMap::iterator> &f, CSyncData & outSync);
|
||||
|
||||
bool GetCurrent(DataBase *db, string& tblname, bool useDisyplay = true);
|
||||
vector<string> Current2Sync(string sflag, vector<string>& curr);
|
||||
|
||||
string GetFullFilenamehash();
|
||||
|
||||
void FreeDB(DataBase *db, bool success = true);
|
||||
DataBase* GetDB(string& tblname, bool & usedisplay);
|
||||
|
||||
JOB_TYPE::JOB_TYPE m_type;
|
||||
vector<string> m_syncdata;
|
||||
vector<string> m_fhsmount;
|
||||
|
||||
CCurretMap m_current;
|
||||
|
||||
bool m_first;
|
||||
};
|
||||
|
||||
#endif // __VALIDATION_H__
|
||||
@@ -0,0 +1,710 @@
|
||||
/***************************************************************************
|
||||
Work 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 "rc_cmove.h"
|
||||
#include "workpool.h"
|
||||
#include "validation.h"
|
||||
#include "synchronization.h"
|
||||
#include "parameter.h"
|
||||
#include "Logger.h"
|
||||
#include "ReportLog.h"
|
||||
|
||||
#include <fcntl.h> /* For O_* constants */
|
||||
#include <sys/stat.h> /* For mode constants */
|
||||
#ifdef _USE_POSIX_SEMAPHORES
|
||||
#include <semaphore.h>
|
||||
#elif defined(_USE_POSIX_LOCK)
|
||||
#ifndef O_CLOEXEC
|
||||
// kernel 2.6.23 부터 지원
|
||||
#define O_CLOEXEC 0
|
||||
#endif // !O_CLOEXEC
|
||||
#endif // _USE_POSIX_SEMAPHORES
|
||||
|
||||
|
||||
#define SLEEP_TIME 1000 //microsecond
|
||||
|
||||
workpool *workpool::m_inst = NULL;
|
||||
|
||||
// work
|
||||
work::work()
|
||||
: m_step(-5), m_exit(false), m_enablesync("0000"), m_networkmode(false)
|
||||
{
|
||||
m_nofi = NULL;
|
||||
pthread_mutex_init(&m_workmutex, NULL);
|
||||
pthread_cond_init(&m_workcond, NULL);
|
||||
#ifdef _USE_POSIX_SEMAPHORES
|
||||
m_worksem = NULL;
|
||||
#elif defined (_USE_POSIX_LOCK)
|
||||
m_workfd = -1;
|
||||
#endif // _USE_POSIX_SEMAPHORES
|
||||
}
|
||||
|
||||
work::~work()
|
||||
{
|
||||
pthread_mutex_destroy(&m_workmutex);
|
||||
pthread_cond_destroy(&m_workcond);
|
||||
}
|
||||
|
||||
void* work::working(void * pdata)
|
||||
{
|
||||
ostringstream msg;
|
||||
work* pObject = reinterpret_cast<work *>(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;
|
||||
vector<string> input;
|
||||
CSyncData syncdata;
|
||||
StringSplit(pObject->m_rundata, "|", input, true);
|
||||
|
||||
if (input.size() == SYNCFILE_FIELD::MAX_FILED) {
|
||||
|
||||
// 서비스 간 동기화 경우 tran_id 제거된 uri 사용하므로
|
||||
// 이 후 사용될 로직에서 편의성을 위해서 tran_id를 붙혀넣음
|
||||
if (pObject->m_type == JOB_TYPE::COPY)
|
||||
input[SYNCFILE_FIELD::uri] = "/" + input[SYNCFILE_FIELD::slave_tran_id] + input[SYNCFILE_FIELD::uri];
|
||||
|
||||
syncdata.push_back(input);
|
||||
|
||||
pObject->RunWork(syncdata);
|
||||
}
|
||||
else {
|
||||
msg << "validation sync file string split caution : [" << pObject->m_rundata << "]";
|
||||
|
||||
if (pObject->m_nofi)
|
||||
{
|
||||
pObject->m_nofi(pObject->m_parm, -1);
|
||||
}
|
||||
CReportLog rlog;
|
||||
|
||||
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
|
||||
{
|
||||
rlog.Write("NOT", "[%s] [%s]", PROG_NAME, msg.str().c_str());
|
||||
}
|
||||
LOGACERR(LERR, msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pObject->m_step = -3;
|
||||
if(pObject->m_exit == false)
|
||||
{
|
||||
pObject->m_step = -4;
|
||||
msg << "Work Thread Error.";
|
||||
LOGACERR(LCRT, msg);
|
||||
if (pObject->m_nofi)
|
||||
{
|
||||
pObject->m_nofi(pObject->m_parm, -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pObject->m_step = -5;
|
||||
/* nothing -- signal exit */
|
||||
}
|
||||
}
|
||||
workpool::getInstance()->ReleaseWork(pObject);
|
||||
pObject->m_step = -6;
|
||||
pthread_mutex_unlock(&pObject->m_workmutex);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
cerr << "work::working end - " << pthread_self() << endl;
|
||||
#endif // _DEBUG
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool work::init()
|
||||
{
|
||||
int nRet = pthread_create(&m_thread, 0, work::working, this);
|
||||
if( nRet )
|
||||
{
|
||||
cerr << "Thread create failed.: errno: " << errno << endl;
|
||||
return false;
|
||||
}
|
||||
srand(time(NULL));
|
||||
solusleep(100);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void work::setexit(bool v)
|
||||
{
|
||||
m_exit = v;
|
||||
pthread_mutex_lock(&m_workmutex);
|
||||
pthread_cond_signal(&m_workcond);
|
||||
pthread_mutex_unlock(&m_workmutex);
|
||||
}
|
||||
|
||||
void work::settargethost(vector<string>& targethost)
|
||||
{
|
||||
m_vectargethost.clear();
|
||||
m_vectargethost.resize(targethost.size());
|
||||
copy( targethost.begin(), targethost.end(), m_vectargethost.begin() );
|
||||
}
|
||||
|
||||
bool work::run(JOB_TYPE::JOB_TYPE type, string rundata, work_notifyfn nofi /* = NULL */, void * parm /* = NULL */)
|
||||
{
|
||||
m_type = type;
|
||||
m_rundata = rundata;
|
||||
|
||||
m_nofi = nofi;
|
||||
m_parm = parm;
|
||||
|
||||
ostringstream msg;
|
||||
msg << "Work Run : 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;
|
||||
_LOGACOUT(LNOT, msg);
|
||||
break;
|
||||
}
|
||||
} while (m_step != -1);
|
||||
|
||||
pthread_cond_signal(&m_workcond);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int work::RunWork(CSyncData &syncdata)
|
||||
{
|
||||
int r = 0;
|
||||
short success = 0;
|
||||
|
||||
ostringstream msg;
|
||||
|
||||
msg << "RunWork Start : " << m_rundata;
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
bool first = true;
|
||||
|
||||
while (m_exit == false && !syncdata.empty())
|
||||
{
|
||||
vector<string> input = syncdata.front();
|
||||
syncdata.erase(syncdata.begin());
|
||||
|
||||
string workhash;
|
||||
|
||||
if (workpool::getInstance()->addworkuri(input, workhash, 180) == false)
|
||||
{
|
||||
msg << "Failed RunWork (add working uri) : " << m_rundata;
|
||||
success = -100;
|
||||
_LOGACOUT(LERR, msg);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _USE_POSIX_LOCK
|
||||
string strlockhome = "/tmp/";
|
||||
string strlock;
|
||||
#endif // _USE_POSIX_LOCK
|
||||
do
|
||||
{
|
||||
// 프로세스 간 동화 목적
|
||||
#ifdef _USE_POSIX_SEMAPHORES
|
||||
// lock
|
||||
if ((m_worksem = sem_open(workhash.c_str(), O_CREAT, 0777, 1)) == SEM_FAILED)
|
||||
{
|
||||
success = -101;
|
||||
sem_unlink(workhash.c_str());
|
||||
msg << "Sem Open Error. [" << m_rundata << "]";
|
||||
_LOGACOUT(LERR, msg);
|
||||
break;
|
||||
}
|
||||
sem_unlink(workhash.c_str());
|
||||
|
||||
// KILL(-9) 로 프로세스 죽을 경우 block 걸림
|
||||
sem_wait(m_worksem);
|
||||
#elif defined(_USE_POSIX_LOCK)
|
||||
strlock = strlockhome + workhash;
|
||||
m_workfd = open( strlock.c_str(), O_RDWR | // open the file for both read and write access
|
||||
O_CREAT // create file if it does not already exist
|
||||
| O_CLOEXEC // close on execute
|
||||
,S_IRUSR | // user permission: read
|
||||
S_IWUSR ); // user permission: write
|
||||
if (m_workfd < 0)
|
||||
{
|
||||
success = -102;
|
||||
msg << "lockf open fail. [" << m_rundata << "] [" << strlock << "] errno [" << errno << "]";
|
||||
_LOGACOUT(LERR, msg);
|
||||
m_workfd = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// 2015.01.15 dadamin
|
||||
// EDEADLK 발생으로 중복 파일 발생하기 때문에 에러시 실패 처리함
|
||||
int l = lockf(m_workfd, F_TLOCK, 0);; // lock the "semaphore"
|
||||
if (l == -1)
|
||||
{
|
||||
success = -102;
|
||||
msg << "lockf fail. [" << m_rundata << "] [" << strlock << "] errno [" << errno << "]";
|
||||
_LOGACOUT(LERR, msg);
|
||||
break;
|
||||
}
|
||||
#endif // # _USE_POSIX_SEMAPHORES
|
||||
|
||||
// validation
|
||||
m_step = 3;
|
||||
CSyncData outsync;
|
||||
success = validation(first, input, outsync);
|
||||
if (success != 0)
|
||||
break;
|
||||
|
||||
if (outsync.empty())
|
||||
{
|
||||
LOG(LINF, "There is no data to work with Synchronization.[%s]", m_rundata.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
// diff work uri & return uri
|
||||
vector<string> verified = outsync.front();
|
||||
if (verified.empty())
|
||||
{
|
||||
success = -101;
|
||||
LOG(LCRT, "Empty Synchronization Data.[%s]", m_rundata.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
string reuri = verified[SYNCFILE_FIELD::uri];
|
||||
|
||||
if (input[SYNCFILE_FIELD::uri] != reuri)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
syncdata.clear();
|
||||
syncdata = outsync;
|
||||
LOG(LDBG, "ReWork... [%s]", m_rundata.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(LCRT, "The other uri returned by tried again.[%s]",
|
||||
reuri.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//synchronization
|
||||
m_step = 4;
|
||||
success = synchronization(verified);
|
||||
if (success != 0)
|
||||
break;
|
||||
} while (false);
|
||||
|
||||
#ifdef _USE_POSIX_SEMAPHORES
|
||||
if (m_worksem)
|
||||
{
|
||||
sem_post(m_worksem);
|
||||
solusleep(SLEEP_TIME);
|
||||
sem_close(m_worksem);
|
||||
//sem_unlink(workhash.c_str());
|
||||
m_worksem = NULL;
|
||||
}
|
||||
#elif defined(_USE_POSIX_LOCK)
|
||||
if(m_workfd != -1)
|
||||
{
|
||||
if (lockf(m_workfd, F_TEST, 0) < 0) {
|
||||
//unlink(strlock.c_str());
|
||||
int eno = errno;
|
||||
if (eno == EACCES || eno == EAGAIN) {
|
||||
//lockf(m_workfd, F_ULOCK, 0);
|
||||
}
|
||||
} else {
|
||||
if (success == 0) {
|
||||
unlink(strlock.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
close(m_workfd);
|
||||
m_workfd = -1;
|
||||
}
|
||||
#endif // _USE_POSIX_SEMAPHORES
|
||||
|
||||
workpool::getInstance()->delworkuri(workhash);
|
||||
|
||||
if (success != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_nofi)
|
||||
{
|
||||
m_step = 6;
|
||||
#ifdef _DEBUG
|
||||
cerr << "Work Thread Notify Call." << endl;
|
||||
#endif //_DEBUG
|
||||
m_nofi(m_parm, success);
|
||||
}
|
||||
|
||||
m_step = 7;
|
||||
msg << "RunWork End : " << m_rundata;
|
||||
_LOGACOUT(LDEV2, msg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int work::validation(bool first, vector<string> &input, CSyncData &syncdata)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
msg << "Valid Start :" << input[SYNCFILE_FIELD::uri];
|
||||
|
||||
_LOGACOUT(LDBG, msg);
|
||||
CValidation validate(m_type, input);
|
||||
validate.SetFHSMount(parameter::getInstance()->getfhsmount());
|
||||
int r = validate.CheckData(first, syncdata);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int work::synchronization(vector<string>& verified)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
if (verified.size() != SYNCFILE_FIELD::MAX_FILED)
|
||||
{
|
||||
msg << "synchronization data string split caution : [" << m_rundata << "]";
|
||||
LOGACERR(LERR, msg);
|
||||
|
||||
return -105;
|
||||
}
|
||||
|
||||
CSynchronization sync(m_type, verified);
|
||||
sync.SetTragetHost(m_vectargethost);
|
||||
sync.SetEnable(m_enablesync.c_str());
|
||||
sync.SetNetworkMode(m_networkmode);
|
||||
sync.SetFHSMount(parameter::getInstance()->getfhsmount());
|
||||
|
||||
int r = sync.Execute();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// work pool
|
||||
workpool::workpool()
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_mutex_init(&m_mutexuri, NULL);
|
||||
pthread_mutex_init(&m_mutextry, NULL);
|
||||
}
|
||||
|
||||
workpool::~workpool()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_mutex_destroy(&m_mutexuri);
|
||||
pthread_mutex_destroy(&m_mutextry);
|
||||
}
|
||||
|
||||
workpool* workpool::getInstance()
|
||||
{
|
||||
if(workpool::m_inst == NULL)
|
||||
{
|
||||
workpool::m_inst = new workpool();
|
||||
}
|
||||
return workpool::m_inst;
|
||||
}
|
||||
|
||||
void workpool::release()
|
||||
{
|
||||
if( workpool::m_inst != NULL)
|
||||
{
|
||||
m_inst->DestroyPool();
|
||||
delete workpool::m_inst;
|
||||
workpool::m_inst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int workpool::CreatePool( int poolcnt /* = 10 */ )
|
||||
{
|
||||
// pool
|
||||
for(int i=0 ; i < poolcnt ; i++)
|
||||
{
|
||||
srand ( time(NULL) );
|
||||
work * w = new work();
|
||||
if( w->init() == false)
|
||||
{
|
||||
delete w;
|
||||
break;
|
||||
}
|
||||
|
||||
//m_pool.insert(make_pair(w, workpool::NOTWORK));
|
||||
m_pool.insert(pair<work *,short>(w, workpool::NOTWORK));
|
||||
}
|
||||
|
||||
if( m_pool.size() < static_cast<unsigned int>(poolcnt) )
|
||||
{
|
||||
DestroyPool();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int workpool::DestroyPool()
|
||||
{
|
||||
map<work*, 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 == workpool::NOTWORK)
|
||||
{
|
||||
work *data = static_cast<work *>(iter->first);
|
||||
data->setexit(true);
|
||||
pthread_join(*data->getworkhandle(), NULL);
|
||||
m_pool.erase(iter);
|
||||
delete (work *) data;
|
||||
}
|
||||
|
||||
//sleep(1);
|
||||
}
|
||||
//m_pool.clear();
|
||||
|
||||
return m_pool.size();
|
||||
}
|
||||
|
||||
work* workpool::GetWorkPool(int timeout)
|
||||
{
|
||||
work * r = NULL;
|
||||
|
||||
int64_t usetime = 0;
|
||||
int64_t out = timeout * 1000 * 1000;
|
||||
|
||||
do
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
map<work*, short>::iterator iter;
|
||||
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
|
||||
{
|
||||
if(iter->second == workpool::NOTWORK)
|
||||
{
|
||||
iter->second = workpool::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);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
} while (r == NULL);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void workpool::ReleaseWork(work *w)
|
||||
{
|
||||
//pthread_mutex_lock(&m_mutex);
|
||||
|
||||
map<work*, short>::iterator iter = m_pool.find(w);
|
||||
if( iter != m_pool.end() )
|
||||
{
|
||||
if(iter->second==workpool::WORKING)
|
||||
iter->second=workpool::NOTWORK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ostringstream msg;
|
||||
msg << "unknown work pool.";
|
||||
LOGACERR(LWAR, msg);
|
||||
}
|
||||
|
||||
//pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
void workpool::printstatus(string prefixed)
|
||||
{
|
||||
int w = 0, n = 0;
|
||||
map<work*, short>::iterator iter;
|
||||
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
|
||||
{
|
||||
if(iter->second == workpool::NOTWORK)
|
||||
{
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
++w;
|
||||
}
|
||||
}
|
||||
|
||||
ostringstream msg;
|
||||
if( prefixed.empty() == false )
|
||||
msg << "[" << prefixed << "]";
|
||||
|
||||
msg << "Work Pool - " <<"total : " << m_pool.size() << "(" << w <<
|
||||
"/" << n << ")";
|
||||
_LOGACOUT(LINF, msg);
|
||||
}
|
||||
|
||||
void workpool::printstatusex(string prefixed)
|
||||
{
|
||||
ostringstream msg;
|
||||
map<work*, short>::iterator iter;
|
||||
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
|
||||
{
|
||||
if(iter->second == workpool::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);
|
||||
}
|
||||
}
|
||||
|
||||
bool workpool::addworkuri(vector<string>& syncdata, string &workkey, int timeout)
|
||||
{
|
||||
bool r = true;
|
||||
|
||||
string key;
|
||||
ostringstream msg;
|
||||
|
||||
if (syncdata[SYNCFILE_FIELD::uri].empty() || syncdata[SYNCFILE_FIELD::slave_tran_id].empty() )
|
||||
{
|
||||
msg << "addworkuri uri(or thran_id) empty caution.";
|
||||
LOGACERR(LERR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
string shash;
|
||||
if (syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
|
||||
{
|
||||
if ( syncdata[SYNCFILE_FIELD::filename_hash].empty())
|
||||
{
|
||||
msg << "addworkuri filename_hash empty caution.";
|
||||
LOGACERR(LERR, msg);
|
||||
CReportLog rlog;
|
||||
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
|
||||
{
|
||||
rlog.Write("ERR", "[%s] [failed work filename_hash empty caution.[uri :%s]]", PROG_NAME, syncdata[SYNCFILE_FIELD::uri].c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t found = syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
|
||||
|
||||
if (found != string::npos)
|
||||
{
|
||||
shash = syncdata[SYNCFILE_FIELD::filename_hash].substr(found + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << "addworkuri not found '/'.[uri: " << syncdata[SYNCFILE_FIELD::uri] << "]";
|
||||
LOGACOUT(LWAR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (shash.empty())
|
||||
{
|
||||
ostringstream t;
|
||||
size_t h = __stl_hash_string(syncdata[SYNCFILE_FIELD::uri].c_str());
|
||||
t << h;
|
||||
shash = t.str();
|
||||
}
|
||||
|
||||
key = syncdata[SYNCFILE_FIELD::slave_tran_id] + "." + shash;
|
||||
|
||||
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;
|
||||
LOGACOUT(LDEV2, msg);
|
||||
|
||||
// try
|
||||
solusleep(SLEEP_TIME);
|
||||
usetime += SLEEP_TIME;
|
||||
|
||||
if(timeout > 0 && usetime > out)
|
||||
{
|
||||
r = false;
|
||||
msg << "Work adduri Timeout." << key;
|
||||
LOGACERR(LERR, msg);
|
||||
|
||||
pthread_mutex_unlock(&m_mutexuri);
|
||||
return false;
|
||||
}
|
||||
goto TRY_ADD_WORK_URI;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add
|
||||
workkey = key;
|
||||
m_workurimap[key] = 1;
|
||||
//pthread_mutex_unlock(&m_mutexuri);
|
||||
|
||||
msg << "Add Work. ######### " << key;
|
||||
LOGACOUT(LDBG, msg);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_mutexuri);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool workpool::delworkuri(string key)
|
||||
{
|
||||
|
||||
pthread_mutex_lock(&m_mutexuri);
|
||||
// deleted
|
||||
m_workurimap.erase(key);
|
||||
pthread_mutex_unlock(&m_mutexuri);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/***************************************************************************
|
||||
Work 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 __WORK_POOL_H__
|
||||
#define __WORK_POOL_H__
|
||||
|
||||
#include <semaphore.h>
|
||||
# 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;
|
||||
|
||||
class work
|
||||
{
|
||||
public:
|
||||
work();
|
||||
~work();
|
||||
|
||||
bool init();
|
||||
bool run(JOB_TYPE::JOB_TYPE type, string rundata, work_notifyfn nofi = NULL, void * parm = NULL);
|
||||
|
||||
void setexit(bool v);
|
||||
void setenablesync(const char* szOn) {m_enablesync = szOn;}
|
||||
void setnetworkmode(int mode) {m_networkmode = mode;}
|
||||
void settargethost(vector<string>& targethost);
|
||||
|
||||
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);
|
||||
|
||||
int RunWork(CSyncData &syncdata);
|
||||
int validation(bool first, vector<string> &input, CSyncData &syncdata);
|
||||
int synchronization(vector<string>& verified);
|
||||
|
||||
private:
|
||||
int m_step;
|
||||
bool m_exit;
|
||||
|
||||
JOB_TYPE::JOB_TYPE m_type;
|
||||
string m_rundata;
|
||||
|
||||
work_notifyfn m_nofi;
|
||||
void* m_parm;
|
||||
string m_enablesync;
|
||||
int m_networkmode;
|
||||
vector<string> m_vectargethost;
|
||||
|
||||
pthread_t m_thread;
|
||||
pthread_cond_t m_workcond;
|
||||
pthread_mutex_t m_workmutex;
|
||||
|
||||
#ifdef _USE_POSIX_SEMAPHORES
|
||||
sem_t *m_worksem;
|
||||
#elif defined (_USE_POSIX_LOCK)
|
||||
int m_workfd;
|
||||
#endif // _USE_POSIX_SEMAPHORES
|
||||
};
|
||||
|
||||
class workpool
|
||||
{
|
||||
public:
|
||||
enum WORK_SATAUSE
|
||||
{
|
||||
WORKING = 0,
|
||||
NOTWORK = 1
|
||||
};
|
||||
|
||||
public:
|
||||
static void init();
|
||||
static workpool* getInstance();
|
||||
static void release();
|
||||
|
||||
int CreatePool( int poolcnt = 10 );
|
||||
int DestroyPool();
|
||||
|
||||
bool addworkuri(vector<string>& syncdata, string &hash, int timeout = 5);
|
||||
bool delworkuri(string key);
|
||||
|
||||
void printstatus(string prefixed = "");
|
||||
void printstatusex(string prefixed = "");
|
||||
|
||||
work* GetWorkPool(int timeout = 0);
|
||||
void ReleaseWork(work *w);
|
||||
|
||||
private:
|
||||
workpool();
|
||||
~workpool();
|
||||
|
||||
private:
|
||||
static workpool* m_inst;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
pthread_mutex_t m_mutexuri;
|
||||
pthread_mutex_t m_mutextry;
|
||||
|
||||
workurimap m_workurimap;
|
||||
|
||||
map<work*, short> m_pool;
|
||||
};
|
||||
|
||||
#endif // __WORK_POOL_H__
|
||||
Reference in New Issue
Block a user